|
|
Examining Special Folders | | Normally, when .NET Programmers manipulate files and folders, we use System.IO and perform tasks like creating a directory, deleting a file etc. Well, Windows has some folders known as Special Folders. 'Special Folders is an enumeration for many well, Special Folders like History, Desktop, History, Startup, Program Files and many more. If you aren't familiar with them, I'd encourage you to visit the link I provided and look through them...I'm sure it will open your eyes to some possible shortcuts and timesavers.
Ok, so how do we use these things and how do they fit into the System.IO namespace? As I mentioned, special folders are merely an enumeration and they belong to the Environment class. As such, you can access them just like you would any other directory or folder.
To find out about a folder or directory (like if it exists, when it was created etc.), you can use either the Static/Shared Directory class or you can use the instance counterpart, DirectoryInfo. Similarly, with files you can use the Shared/Static File or the instance counterpart, FileInfo. A few articles back , I show you how to enumerate a directory. I mention that you could make it a lot more powerful using Recursion. So, let's walk through this:
First, include your namespace references (in this case, System.IO):
To find out about a Special Folder, you can interrogate the Environment class. In this case, since I know that their is a 'Favorties' special folder that contains all of my Internet Explorer favorites and that's what I want to access, I'll reference it explicitly:
DirectoryInfo di = new DirectoryInfo(System.Environment.GetFolderPath(Environment.SpecialFolder.Favorites));
|
All I'm doing here is declaring and instantiating an new instance of a DirectoryInfo class and passing a reference to the Favorites Special Folder via the constructor. At this point, assuming their is a Favorites folder and we have permission to access it, our 'di' will know all about it. But now that I know the Path to it, what good does that do me? How can I extract any of the favorites or links from it? To do that, we'll need to walk the folder and each of its folders and list the files. So, I'll drag a TreeView control on to a blank form and insert a button onto it. This probably isn't a realistic example but it should server to illustrate how things work:
Behind the button's click event, I'm going to use the 'di' declaration above and then pass it to a function I called EnumerateFavorites(). Hence, the call will look like this:
DirectoryInfo di = new DirectoryInfo(System.Environment.GetFolderPath(Environment.SpecialFolder.Favorites));
EnumerateFavorites(di);
|
All the work however, is done in EnumerateFavorites:
private void EnumerateFavorites(DirectoryInfo dii)
{
tv.Nodes.Add(dii.FullName);
int i = tv.Nodes.Count-1;
foreach(DirectoryInfo dI in dii.GetDirectories())
{
EnumerateFavorites(dI);
}
foreach(FileInfo fi in dii.GetFiles())
{
tv.Nodes[i].Nodes.Add(fi.FullName);
}
} |
To see what's going on behind the scenes in the IL Instructions, the disassembly code is provided as well (Yes, it's amazing how the .NET Languages encapsulate IL Instructions):
ILDASM.exe Output for the EnumerateFavorites Method:
.method private hidebysig instance void EnumerateFavorites(class [mscorlib]System.IO.DirectoryInfo dii) cil managed
{
// Code size 206 (0xce)
.maxstack 4
.locals init ([0] int32 i,
[1] class [mscorlib]System.IO.DirectoryInfo dI,
[2] class [mscorlib]System.IO.FileInfo fi,
[3] class [mscorlib]System.IO.DirectoryInfo[] CS$00000007$00000000,
[4] int32 CS$00000008$00000001,
[5] class [mscorlib]System.IO.FileInfo[] CS$00000007$00000002,
[6] int32 CS$00000008$00000003)
IL_0000: ldarg.0
IL_0001: ldfld class [System.Windows.Forms]System.Windows.Forms.TreeView WindowsApplication6.Form1::tv
IL_0006: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection [System.Windows.Forms]System.Windows.Forms.TreeView::get_Nodes()
IL_000b: ldarg.1
IL_000c: callvirt instance string [mscorlib]System.IO.FileSystemInfo::get_FullName()
IL_0011: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TreeNode [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection::Add(string)
IL_0016: pop
IL_0017: ldarg.0
IL_0018: ldfld class [System.Windows.Forms]System.Windows.Forms.TreeView WindowsApplication6.Form1::tv
IL_001d: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection [System.Windows.Forms]System.Windows.Forms.TreeView::get_Nodes()
IL_0022: callvirt instance int32 [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection::get_Count()
IL_0027: ldc.i4.1
IL_0028: sub
IL_0029: stloc.0
IL_002a: ldarg.1
IL_002b: callvirt instance class [mscorlib]System.IO.DirectoryInfo[] [mscorlib]System.IO.DirectoryInfo::GetDirectories()
IL_0030: stloc.3
IL_0031: ldc.i4.0
IL_0032: stloc.s CS$00000008$00000001
IL_0034: br.s IL_0048
IL_0036: ldloc.3
IL_0037: ldloc.s CS$00000008$00000001
IL_0039: ldelem.ref
IL_003a: stloc.1
IL_003b: ldarg.0
IL_003c: ldloc.1
IL_003d: call instance void WindowsApplication6.Form1::EnumerateFavorites(class [mscorlib]System.IO.DirectoryInfo)
IL_0042: ldloc.s CS$00000008$00000001
IL_0044: ldc.i4.1
IL_0045: add
IL_0046: stloc.s CS$00000008$00000001
IL_0048: ldloc.s CS$00000008$00000001
IL_004a: ldloc.3
IL_004b: ldlen
IL_004c: conv.i4
IL_004d: blt.s IL_0036
IL_004f: ldarg.1
IL_0050: callvirt instance class [mscorlib]System.IO.FileInfo[] [mscorlib]System.IO.DirectoryInfo::GetFiles()
IL_0055: stloc.s CS$00000007$00000002
IL_0057: ldc.i4.0
IL_0058: stloc.s CS$00000008$00000003
IL_005a: br.s IL_00c5
IL_005c: ldloc.s CS$00000007$00000002
IL_005e: ldloc.s CS$00000008$00000003
IL_0060: ldelem.ref
IL_0061: stloc.2
IL_0062: ldloc.2
IL_0063: callvirt instance valuetype [mscorlib]System.IO.FileAttributes [mscorlib]System.IO.FileSystemInfo::get_Attributes()
IL_0068: box [mscorlib]System.IO.FileAttributes
IL_006d: call instance string [mscorlib]System.Enum::ToString()
IL_0072: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_0077: ldarg.0
IL_0078: ldfld class [System.Windows.Forms]System.Windows.Forms.TreeView WindowsApplication6.Form1::tv
IL_007d: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection [System.Windows.Forms]System.Windows.Forms.TreeView::get_Nodes()
IL_0082: ldloc.0
IL_0083: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TreeNode [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection::get_Item(int32)
IL_0088: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection [System.Windows.Forms]System.Windows.Forms.TreeNode::get_Nodes()
IL_008d: ldloc.2
IL_008e: callvirt instance string [mscorlib]System.IO.FileSystemInfo::get_FullName()
IL_0093: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TreeNode [System.Windows.Forms]System.Windows.Forms.TreeNodeCollection::Add(string)
IL_0098: pop
IL_0099: ldarg.0
IL_009a: ldfld class [System.Windows.Forms]System.Windows.Forms.RichTextBox WindowsApplication6.Form1::rtb
IL_009f: dup
IL_00a0: callvirt instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
IL_00a5: ldloc.2
IL_00a6: callvirt instance string [mscorlib]System.IO.FileSystemInfo::get_FullName()
IL_00ab: callvirt instance string [mscorlib]System.String::ToString()
IL_00b0: ldstr "\r\n"
IL_00b5: call string [mscorlib]System.String::Concat(string,
string,
string)
IL_00ba: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Text(string)
IL_00bf: ldloc.s CS$00000008$00000003
IL_00c1: ldc.i4.1
IL_00c2: add
IL_00c3: stloc.s CS$00000008$00000003
IL_00c5: ldloc.s CS$00000008$00000003
IL_00c7: ldloc.s CS$00000007$00000002
IL_00c9: ldlen
IL_00ca: conv.i4
IL_00cb: blt.s IL_005c
IL_00cd: ret
} // end of method Form1::EnumerateFavorites |
ILDASM.exe Output And the button Click that starts everything:
.method private hidebysig instance void button4_Click(object sender,
class [mscorlib]System.EventArgs e) cil managed
{
// Code size 26 (0x1a)
.maxstack 2
.locals init ([0] class [mscorlib]System.Collections.ArrayList all,
[1] class [mscorlib]System.IO.DirectoryInfo di)
IL_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
IL_0005: stloc.0
IL_0006: ldc.i4.6
IL_0007: call string [mscorlib]System.Environment::GetFolderPath(valuetype [mscorlib]System.Environment/SpecialFolder)
IL_000c: newobj instance void [mscorlib]System.IO.DirectoryInfo::.ctor(string)
IL_0011: stloc.1
IL_0012: ldarg.0
IL_0013: ldloc.1
IL_0014: call instance void WindowsApplication6.Form1::EnumerateFavorites(class [mscorlib]System.IO.DirectoryInfo)
IL_0019: ret
} // end of method Form1::button4_Click
| Basically I'm just passing in a DirectoryInfo object which corresponds to a directory or folder in the Favorites folder (I could just as easily have used the some other method like GetLogicalDrives to get some directories and pass these into a function to enumerate them. Anyway, each time a DirectoryInfo is passed to the function, it's FullName property is added as a root node to the TreeView. In order to add child nodes to a TreeView node, you need to know its numeric Index, which I'm keeping track of with the variable 'i'. Each time through I add a node, and then set i equal to the count of nodes in the Nodes collection less one (it's zero based). That way, when I add child nodes to it, I know where I am. There are other ways to get here, but as far as examples go, this makes what I'm doing pretty easy to follow.
Now, after I add the node I use the GetDirectories() method of the DirectoryInfo class. If I don't find any (which means that a directory doesn't have any subdirectories), than I walk through it, adding each FileInfo's .FullName property as a child node. However, if a directory does have subdirectories, I call the EnumerateFavorite method, passing it in the currect DirectoryInfo (which starts the process all over again until we no longer have any directories. At that point, we fill the TreeView with that names of each file and go back up the stack). I'd like to point out though that using this methodology will yield a Treeivew that's not exactly heirachical b/c every directory will be inserted at the same level. So a subdirectory will appear in the same place as a root directory. The purpose of this article was to illustrate using simple recursion and using the SpecialFolders enumeration of the Environment class. If you want to enumerate directories and create a Windows Explorer like interface this tutorial shows you how to do it. |
|