SYSTEMS STATUS

All servers are running at optimum levels.

Reading File Attributes in VB.NET without Third-Party Tools

Posted August 10th, 2011 5:38pm by Ariel Villanea

Recently, while working on a program for a customer, I had to figure out how to read file-attributes of any specified file on a Windows-based computer. Of course, this was part of a brand new request and the task itself was something I’d never attempted before.

Originally, I thought, “Well, this can’t possibly be that hard” but as it turns out, I couldn’t find any examples online that didn’t involve using ActiveX or even Flash to do this. I found this rather ridiculous. So, the general public is telling me that I can’t call a native VB.NET function or built-in Windows service to simply read a file’s attributes? Honestly, I refused to believe that, so I started looking into things a bit more.

What really struck me as odd at this point was that upon poking around in curiosity, I noticed that Windows is somehow already doing exactly what I’m trying to do.

For a quick example, navigate to your sample videos or sample photos on your windows computer. As far as I know, Vista and 7 computers both display file information on the bottom of Windows Explorer. (XP might also do the same, can’t say I recall either way!)

So, how can I access this information programmatically using VB.NET? Some extra research revealed to me the existence of a file in windows called Shell32.dll. Now, if you’re a veteran, you may be fully aware of what this is already. I had heard of the file, but I don’t think I was ever aware of what it really was. Simply put, Shell32 one of the essential parts of a Windows computer. Much like Explorer.exe, if you don’t have Shell32.dll, you don’t have a Windows computer. So, in line with Microsoft’s tradition of having great tools and never really making the public aware of them, I found out that Shell32 had the ability to do exactly what I was looking for; along with various other functions!

So let’s start our project, I’ll be using Visual Studio 2010, but much of this can be done on any version with .NET.

I’ll be naming my project “File Data Scanner”; you can name it anything you like, but from this point on, that is what I will refer to the project as.

We’ll be making the File Data Scanner as a Windows Forms Application. Despite Console Applications being a bit more simple to display examples for, I feel a Windows Forms Application is better since it’ll allow us to input and show information for the files in a more straight-forward manner. Moving on!

Go ahead and set up your form similar to how I’ve set mine up above. Keep in mind that the only reason I’ve made the text fields so large is because that way, I can see as much information within them as possible. Don’t forget to make the bottom one multi-line and add vertical scroll bars!

Next, we want to make our Display Data button actually… display data!

So now, it was a matter of accessing the functions. Luckily, I’ve dealt with various different DLLs from Dart to Telerik, so it was easy to make a reference to this DLL!

First, right click on your project and then click on “Add Reference…” like below:

Now, on the following screen, there are two ways to find the Shell32 DLL to make your reference. You could use the browse functionality to hunt down the file within your System 32 folder… or, just find it in the COM list under “Microsoft Shell Controls And Automation.” The list can be searched through by typing, so if you just type “Microsoft Shell” you should find it easily. If it’s not in this list, I recommend you just use the Browse tab to find it in your System 32 folder.

Click “OK” and we’ve made our reference to the Microsoft Shell Controls and Automation COM Object (a.k.a. Shell32.dll)!

Now, back on our form, double-click on the “Display Data” button, or “btnDisplayData” and we’ll enter the click action for the button. Within the click action, we’ll need to create 4 different objects in a certain order. First, create the App Type, then the Shell Instance, the Shell Folder and finally, the Shell Folder Item. Also! Keep in mind you will have to import System.IO for this.

Dim shellapptype As Type = Type.GetTypeFromProgID("Shell.application")
Dim shell As Object = Activator.CreateInstance(shellapptype)
Dim objFolder As Shell32.Folder = shell.NameSpace(Path.GetDirectoryName(txtFilePath.Text))
Dim objFile As Shell32.FolderItem = objFolder.ParseName(Path.GetFileName(txtFilePath.Text))

The creation of “shellapptype” and “shell” are basically to tell the program that we’ll be using Shell32 for a few functions now. Similar to how you begin a reference to a webservice! The “objFolder” is basically the folder that we’ll be working within while reading file information and “objFile” is the file we’ll be retrieving information about!

Keep in mind! We’re assuming that a “Perfect User” is using this program, so we’re not going to be worrying about checking to see if the file exists or if the file path is even valid. Though if you choose to use this method to acquire file information, it’s recommended you take those steps as well!

So at this point, the example I was looking at was actually using XP to call items from Shell32. This quickly became a problem for me. The way to retrieve attributes from a file with Shell32 is using the following code:

Dim FileInformation As New StringBuilder
FileInformation.AppendLine(objFolder.GetDetailsOf(objFile, 1))
FileInformation.AppendLine(objFolder.GetDetailsOf(objFile, 2))
FileInformation.AppendLine(objFolder.GetDetailsOf(objFile, 3))
FileInformation.AppendLine(objFolder.GetDetailsOf(objFile, 4))
FileInformation.AppendLine(objFolder.GetDetailsOf(objFile, …))
txtFileInformation.Text = FileInformation.ToString

Easy to grab items if I know their index, right? So what’s the problem?

My development computer is running Vista, the example is for XP and the user base of my application will be using XP, Vista and 7.

Still don’t see a problem?

XP only has 40 items to choose from, Vista and 7 have 266, and the items vary from version to version. So now, we’re faced with another hurdle: to make this program universal, we need to address the file attributes for each file depending on OS version.

So how do we get our OS version? Simple!

Environment.OSVersion.Version” will solve that issue for us! Using that universal function, we can check to see what version the user is using.

Upon some testing, I discovered that using “Environment.OSVersion.Version.Major", XP comes back as 5 and Vista comes back as 6. Makes sense, right? So 7, obviously, must be 7… right? WRONG!

Windows 7 also comes back as 6, just like Vista.

This struck me as odd, so I looked at “Environment.OSVersion.Version.Minor", and it turns out that Vista is 0 and 7 is 1. So, the problem of checking version numbers is now solved!

But how do we know which attributes to return? Easy!

We’ll figure it out by looping through the attributes! We’ll loop through the items from -1 to 300.

The reason is; we know that Vista and 7 allow up to 266 attributes and -1 happens to store the item’s tooltip value.

So here is our final code!

'Create Shell App Type and set it to Shell.Application.
Dim shellapptype As Type = Type.GetTypeFromProgID("Shell.application")
'Create the Shell Instance.
Dim shell As Object = Activator.CreateInstance(shellapptype)
'Create the Shell Folder.
Dim objFolder As Shell32.Folder = shell.NameSpace(Path.GetDirectoryName(txtFilePath.Text))
'Create the Shell Folder Item.
Dim objFile As Shell32.FolderItem = objFolder.ParseName(Path.GetFileName(txtFilePath.Text))
'Create your File Information string builder.
Dim FileInformation As New StringBuilder

'Find OS version and add it to the data returned.
Select Case System.Environment.OSVersion.Version.Major
Case 5
FileInformation.AppendLine("Windows XP")
Case 6
Select Case System.Environment.OSVersion.Version.Minor
Case 0
FileInformation.AppendLine("Windows Vista")
Case 1
FileInformation.AppendLine("Windows 7")
End Select
End Select

For i = -1 To 300
FileInformation.AppendLine(i & ": " & objFolder.GetDetailsOf(objFile, i))
Next

txtFileInformation.Text = FileInformation.ToString

Finally, we end up with the following outcome:

Obviously, if a file does not have attributes filled in or they don’t pertain to the file, it will return blanks. Unfortunately, I’m not aware of any way of using Shell 32 to determine names of these properties, but I’ve provided a list of file attributes with their numbers on the source code for this project.

I certainly hope this article was helpful to you! Always keep in mind that ePolk specializes in writing custom software that fits the customer’s needs to a T and we’d definitely love to take on your custom projects!