Page 3 of 5
Coping with Windows 7 (Vista) UAC
The problem of access has been made more difficult by the tightening of security under first Vista and subsequently under Windows 7. When you run a .NET application then generally it will run with the permissions of the currently logged in user. However even if the user is logged in as an administrator the UAC will deny administrator privileges unless you use Run As Administrator. This works well if you are running a finished .NET application but it doesn't work well while debugging. The solution is to use the Add,New Item command to add an application manifest to the project. Following this you will find that you have a new file called app.manifest containing a lot of XML you might never have seen before. You can ignore most of it but change the line:
You can do this by copying on of the alternative lines provides as comments as part of the template. After this Visual Studio will restart and the application will run at administrator level - assuming you are a member of the administrator group.
This change should cure any access denied problems with the application but if not check that the file isn't read-only and that its security setting allows read/write for the administrator group.
The StgOpenStorage function returns an IStorage interface – the good news is that this works and we can now start to manipulate the structure storage using the functions it defines.
In most cases the first thing we need to do after opening a structured storage file is to find out what's stored in it. This is a two-step process – first get an enumerator and second use the enumerator's Next function to retrieve STATSTG structs which describe each storage element.
Getting the enumerator is easy:
0, out SSenum);
We can now use a loop to step through the STATSTG structs. The only minor complication is that we have to pass an array of STATSTG structs and say how many we want to retrieve at each use of Next. In most cases its simpler to retrieve just one:
Com Types.STATSTG SSstruct =
The Next function tries to return the number requested, one in this case, but will return fewer if there aren't enough remaining in the enumeration. The number actually returned is given by the final parameter and this is used to stop the iteration:
if (NumReturned != 0)
textBox1.Text = textBox1.Text +
SSstruct.pwcsName + " " +
In this example the name of each of the structure storage elements is added to a Textbox along with the element's type.
If you run this on a Thumbs.db file you will see that there are elements called 1,2,3 and so on and one called Catalog. All of these are of type 2. To discover what the type codes mean we need the STGTY enumeration. Unfortunately, at the time of writing, Pinvoke.Net didn't have a suitable definition but one is easy to construct from the C++ definition given in the documentation:
enum STGTY :int
STGTY_STORAGE = 1,
STGTY_STREAM = 2,
STGTY_LOCKBYTES = 3,
STGTY_PROPERTY = 4
You can see that there are four possible types stored in a structured storage file. All of the elements in Thumbs.db are streams, i.e. data files that can be written and read in the usual way.
Elements of type 1 are storage objects and these can contain complete filing systems just like the root storage object we have opened. You can think of this as being the analogy of sub-directories within a root directory. What this means is that to find out everything stored in a structured storage you have to open each storage object in the top level storage object and enumerate what they contain.
Clearly this is a job for a recursive function but given that Thumb.db files only contain a single top level storage object this is an exercise left for the reader. The remaining two possibilities are special types of "file". Type 3 is a byte array and type 4 is a property set of property name value pairs. In most cases you can ignore these but if you need to know more look up the interfaces and helper functions with PROP included in their name and ILockBytes.