Post

Further Adventures in WinRT - Part 1

Working with WinRT, well, I’m just going to say it… sucks! I’m past the “who moved my cheese” phase; so that’s not why I’m making that statement. It sucks because it is not completely thought out, requires that you have to jump through hoops that were solved by many other API stacks many years ago, and contains way too many conflicting stories, requires crossing too many API layers… in other words, it’s either incomplete or not very well thought out. With that said, there’s not much I can do about it; if I want to target the Windows Store, I have no choice but to roll up my sleeves and attempt to trudge through the mess to accomplish the task at hand.

These adventures will be done in a scenario(s) / solution format. So let’s get started.

Background

It doesn’t matter if we have a desktop, tablet, Intel machine, ARM machine or even a Windows Phone 8 device; storage space is limited. As an application author, I want to be a good citizen. It’s bad form to write to the storage device(s) blindly without regard to the amount of storage space that is left. Windows, as a whole, (to the best of my knowledge) does not work very well when it runs out of space (temp files anyone). A Windows server is nearly impossible to log into remotely if the disk free space has reached 0. This should never happen and the authors of software should play nice.

Scenario

So we want to write something to the storage device. We want to be a good citizen; so let’s see if we actually have enough storage space without risk of bringing the system to it’s knees. How do we do this?

Adventure

As a .NET developer using a framework that has been around for over a decade, the following “just works”.

1
2
Dim drive = New System.IO.DriveInfo(driveName)
Dim available = drive.TotalFreeSpace

Sorry… not available in WinRT. After doing a bit of research, I was unable to determine any way of any kind to accomplish this task using the WinRT API.

WinRT is also “sand boxed”; meaning that it does a tremendous (or hideous depending on your view) job of isolating what can and cannot be leveraged on your device without your permission. Even given permission, there is only so much that a WinRT application can do; which means that there is a ton of things that it can’t.

So if it isn’t in the WinRT API, your screwed… or are you?

Solution

As it turns out there appears to be a few “blessed” Windows API’s that are allowed to be P/Invoked from a WinRT .NET application. One of these is the Kernel32 GetDiskFreeSpaceEx function. To utilize it, you’ll need to create a “reference” to it by adding the following to a class.

1
2
3
4
5
Declare Auto Function GetDiskFreeSpaceEx Lib "kernel32.dll" (
  ByVal lpDirectoryName As String,
  ByRef lpFreeBytesAvailable As ULong,
  ByRef lpTotalNumberOfBytes As ULong,
  ByRef lpTotalNumberOfFreeBytes As ULong) As Boolean

So one way to get the free space is to use a reference to your application folder…

1
2
3
4
5
6
7
8
9
10
11
12
Dim available, total, totalFree As ULong
Dim appFolder = Windows.Storage.ApplicationData.Current.LocalFolder
If GetDiskFreeSpaceEx(appFolder.Path, available, total, totalFree) Then
  Return available
Else
  Dim err = Marshal.GetLastWin32Error
  If err = 5 Then
    ' Access Denied
  Else
    Stop
  End If
End If

Seems relatively straight forward and painless (once you figure out the Kernel32 declaration, understand how p/invoke, marshaling and the different method that “error handling” works in the Windows API — or you just blindly copy/paste what someone else does and hope for the best). Also, even though it’s pretty obvious, you can see that it takes a few more lines of code to accomplish the same task compared to the .NET BCL (Base Class Libraries); appears to be one of those “one step forward, two steps back” kind of days.

Here’s the problem, what if your documents folder isn’t on the same storage device as your application? Even if your application has been given permission to read/write to the documents location, you can not pass the path to the documents location to get a result.. instead, you get an Access Denied message.

So I experimented further and found that passing D:\ also fails.

Hmmmm…

I then attempted, as last ditch effort, D:… it works. WTF?!?!?!

Is this documented anywhere? Not that I could find. What a wonderful (WinRT) time we live in. At least I can get done what I need to get done, moving on.

See you in the next adventure.

This post is licensed under CC BY 4.0 by the author.