Launching Windows Store Apps From Desktop

As Windows 8 adoption is growing (as a matter of fact, in the first month there were more than 40 million licenses sold), so is the number of Windows Store applications. I use some of the Windows Store delivered applications, such as Music, Netflix, Bing Weather and Bing Search quite often, but I also spend a lot of time in Visual Studio, which means that I am not in the Windows 8 shell, but I have access to the taskbar. I was looking for a quick way to launch those applications from the desktop mode, and found an easy solution – URI associations.

Some Windows Store applications come with custom URI associations, which means that the application can be launched from anywhere in the OS, given that there is a scheme-to-app association in the system.

Registered application URI schemes are available in the Windows Registry. For example, here are some of them that are bound to stock apps:

  • Bing Finance – bingfinance:
  • Maps – bingmaps:
  • News – bingnews:
  • Search – bingsearch:
  • Sports – bingsports:
  • Travel – bingtravel:
  • Weather – bingweather:
  • Music – microsoftmusic:
  • Video – microsoftvideo:
  • Messages – mschat:
  • Calendar – wlcalendar:
  • People – wlpeople:
  • Games – xboxgames:

All these associations are located in HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations. Other applications can also register their own URI schemes, so the list might be quite long.

Here comes the tricky part. If you just create a shortcut to, let’s say, microsoftmusic: (talking about a .lnk file), you will quickly realize that Internet Explorer will be intercepting the URI scheme association and will be asking you if you want to launch the application.

What you could have, instead, is a PowerShell script, wrapped like this:

$Cmdy = new-object -comObject "Shell.Application"
$Cmdy.ShellExecute('microsoftmusic:')

Save this file anywhere. For this blog post, I named the file Music.ps1. If you worked with PowerShell before, you know by now that in order to execute a PS script, you need to right-click on the file and select Open with PowerShell. However, this process can once again be simplified. Create a new shortcut that executes the script, having the target pointing to the script:

powershell.exe "C:\Users\Den\Desktop\Music.ps1"

By default, the security policy for PowerShell scripts is quite strict. To allow running scripts directly, open the PowerShell console as an administrator and run this command:

set-executionpolicy remotesigned

More details about the set-executionpolicy cmdlet can be found here.

SECURITY WARNING: Before setting the script execution policy for your system, make sure you are aware of potential security implications, as this will remove the “no script” restriction on your Windows instance.

Once this is complete, you’ve got yourself a fully-functioning shortcut to a Windows Store application in desktop mode.

Adding SkyDrive Upload Support to Your Windows Phone App

Multiple applications that are already in the Windows Phone Marketplace operate with a variety of content, such as pictures, text files and music. More often than not, that content is stored locally, in the application isolated storage, and although it is a good way to preserve that content, this method is bound to create some inconveniences in case the user decides to switch phones or do a complete device reset. To avoid this, developers can leverage the Microsoft Live SDK, specifically the SkyDrive API that is exposed through it.

To make my case more realistic, I am going to bring up my Windows Phone project – Beem (you can find the free version here and the donation build here). As I am expanding the functionality base for the Beem Plus client, I decided that I need to do something to allow users to back up the stream recordings that they have. Those are MP3 files stored internally, captured directly from the incoming radio stream.

The interesting part about these recordings is the fact that their length varies. One user might record a 10 second track, another one might have hours of online podcasts. Therefore, it would be logical to let them backup that data, in case something goes wrong. The Microsoft Live SDK comes with out-of-the box support for Windows Phone, so once you download and install the SDK, all you need to do is add a Microsoft.Live and Microsoft.Live.Controls assemblies to the project. Those should be already present in Visual Studio, in the Extensions section in the References dialog.

It is important to mention that before, it was not possible to upload MP3 files to SkyDrive from third-party applications. My workaround to that was simply adding a .wav at the end of the uploaded file name. An extension mismatch would not cause any problems during playback on a Windows machine, and if necessary, it can easily be swapped manually. Since then, the restriction has been lifted and SkyDrive supports MP3 uploads.

You will integrate the Microsoft Account authentication in your application by adding a SignInButton control, also specifying the scope of your integration with the user account. This is a built in measure that prevents applications from abusing the system by notifying the user about the actions the application will be able to perform on the account.

Basic Setup

SignInButton is added in the XAML layer, and a sample snippet would look like this:

<live:signinbutton x:name="btnSignIn" clientid="CLIENT_ID_HERE" scopes="wl.signin wl.basic wl.offline_access wl.skydrive wl.skydrive_update" branding="Skydrive" texttype="Connect" visibility="Collapsed"></live:signinbutton>

First things first, take a look at the declared scopes. The application will be able to sign the user in (wl.signin), access the basic profile information (wl.basic), access the user account when the user is not necessarily online, allowing me to preserve the login information so that there is no repetitive login once the app successfully performed the authentication (wl.offline_access), access the basic SkyDrive metadata (wl.skydrive) and update the file layout in the SkyDrive storage (wl.skydrive_update).

The ClientID identifies your application and can be obtained here. Branding and TextType determine the appearance of your button, allowing you to customize the displayed logo and caption.

When the user clicks on the button for the first time, he will be prompted with a web authentication page, where he will be asked to enter his Microsoft Account credentials. Once the account passes the verification, the user will be prompted with another web page, that shows the permissions the application requests. It is important that you declare only the necessary permissions when declaring the scopes.

Once Yes is clicked in the dialog, the session information will be automatically stored in the application if necessary, so you don’t have to worry about manually preserving those. Every time the authentication engine is invoked, the SessionChanged event handler is invoked, so make sure you hook it to the button:

btnSignIn.SessionChanged += App.MicrosoftAccount_SessionChanged;

As a result, you can potentially obtain a LiveConnectSession, that will be consequently used to perform any request on the Microsoft service endpoints. However, you also need to make sure that that account was actually successfully connected, since the user can block the application.

public static void MicrosoftAccount_SessionChanged(object sender, Microsoft.Live.Controls.LiveConnectSessionChangedEventArgs e)
{
if (e.Status == Microsoft.Live.LiveConnectSessionStatus.Connected)
{
MicrosoftAccountClient = new LiveConnectClient(e.Session);
MicrosoftAccountSession = e.Session;
MicrosoftAccountClient.GetCompleted += client_GetCompleted;
MicrosoftAccountClient.GetAsync("me", null);
}
else
{
Binder.Instance.MicrosoftAccountImage = "/Images/stock_user.png";
Binder.Instance.MicrosoftAccountName = "no Microsoft Account connected";
MicrosoftAccountClient = null;
}
}

The call to me/picture will return the URL for the profile picture for the currently authenticated user. Notice that I am getting the results by referencing the key names. When the raw JSON data is returned on a call, a dictionary is automatically created that contains the key-value pairs, that makes it easier to get the data without having to re-parse the data. The RawResult property still exposes the raw JSON.

Uploading the File

Once a file is already present in the isolated storage and the Microsoft Account is connected to the application, it is extremely easy to initiate the uploading process. Before doing that, however, you need to consider that every user has limited SkyDrive quota. The default amount of allocated storage for current users is 7GB, so make sure that you check whether there is any available space for the file that you are about to send. To do this, you need to perform a call to me/skydrive/quota.

client = new Microsoft.Live.LiveConnectClient(App.MicrosoftAccountSession);
client.GetCompleted += client_GetCompleted;
client.GetAsync("me/skydrive/quota", null);

This call will return two values – total quota and available space. Before the upload, compare the byte size of the file and the available space.

if (e.Result.ContainsKey("available"))
{
    Int64 available = Convert.ToInt64(e.Result["available"]);
    byte[] data = RecordManager.GetRecordByteArray(Binder.Instance.CurrentlyUploading);

    if (available >= data.Length)
    {
        MemoryStream stream = new MemoryStream(data);

        client = new LiveConnectClient(App.MicrosoftAccountSession);
        client.UploadCompleted += MicrosoftAccountClient_UploadCompleted;
        client.UploadProgressChanged += MicrosoftAccountClient_UploadProgressChanged;
        client.UploadAsync("me/skydrive", Binder.Instance.CurrentlyUploading,
            stream, OverwriteOption.Overwrite);
        grdUpload.Visibility = System.Windows.Visibility.Visible;
        ApplicationBar.IsVisible = false;
    }
    else
    {
        MessageBox.Show(@"Looks like you don't have enough space on your SkyDrive.
Go to http://skydrive.com and either purchase more space or clean up the existing storage.", "Upload",
            MessageBoxButton.OK);
    }
}

If there is available space, simply create a new instance of LiveConnectClient, with the current LiveConnectSession (you can keep it in the App class for global access) and use UploadAsync to pass the internal path to the file, the file name, the file stream and the overwrite method. By default, all files are being overwritten. Remember, however, that when you are specifying the path to the folder you want to upload the file to, you cannot use the normal path format, but rather refer to folders by their ID. You can find more details about it in one of my previous articles. For some folders, however, you can directly specify the path. Example: me/skydrive/my_documents.

UploadCompleted and UploadProgressChanged can be used to define application behavior during and after the upload, such as displaying a popup that shows the current upload percentage.

Making The Account Accessible App-Wide

One interesting fact worth mentioning in case you declared wl.offline_access as a pre-determined scope. The default behavior for the application is to authenticate the Microsoft Account when the page with a valid SignInButton is hit. My intent for Beem was to keep the SignInButton in the application settings, where it is expected by the end-user. However, in this case the user will only be automatically authenticated when the Settings page would be opened, which is something that does not happen too often, in contrast with the multitude of other pages that are being used internally.

The workaround to this small issue is really simple – make sure that you add a SignInButton with exactly the same scopes and ClientID in the main application page, and set its Visibility property to Collapsed. You will need to wire it up to the SessionChanged event handler, that can be the same for both sign-in buttons used in the application.

Trick or Treat – URI Associations In Windows Phone 8 Outside Bing Vision

With the release of the new Windows Phone 8 SDK, the developers are now able to create URI associations, where their application can be launched from the context of another application. For example, I can register a den: URI scheme to pass specific information to my application from any other installed application or resource, such as an email or a text message. That way, my application is no longer a standalone entity and it can interact easily with other applications in the Windows Phone ecosystem.

There is one interesting aspect, however. Custom URI schemes are not recognized by Bing Vision, which might be a problem if you generated a QR code that should launch your application. You will be able to launch http:// URLs, but custom applications will remain in their separate frame, out of reach of the stock app.

Although this might seem like an issue, it can easily be mitigated by using standard HTML redirect. Since Bing Vision correctly handles URLs, and Internet Explorer on Windows Phone supports redirects, you have a couple of options, one of them suggested by Nikola Metulev.

Have the user navigate to a URL that will redirect to the custom URI schema. Create a HTML page, that has the following source:

                        

What will happen here is when the user will navigate to this page from a Windows Phone, he will get redirected to the custom URI that was specified as the redirect target. It is not possible to enter custom URLs that do not follow the HTTP format in the Internet Explorer address bar, but you can still rely on content links and redirects. Of course, you could also use a third-party URL shortening web service that supports custom URI schemas, such as is.gd. You can shorten an URL and have a QR code automatically generated. That URL can be something like den:awesome, and from it you will obtain a valid HTTP URL that will then trigger the application launch.