Inter-Process communication with protocol association in WinRT – Part 3

The previous post presented how file association is used to exchange information between Windows Store Apps (WSAs) and Desktop Apps (DAs). The same kind of feature can be provided by the protocol association.

WARNING: all these techniques are violating the point 3.1 from the Windows Store Requirements that states: “Your app may only depend on software listed in the Windows Store“. Therefore, you should not use them for a WSA that you plan to publish into the Windows Store because it will be rejected.

How to activate another application?

From a WSA, the Launcher.LaunchUriAsync method activates another application that is associated to a given protocol.

The LauncherOptions is set to avoid unnecessary popup to the end user.

LauncherOptions options = new LauncherOptions();
options.DisplayApplicationPicker = false;
options.TreatAsUntrusted = false;
// See Mainform.cs for the details of the daipp protocol syntax
Uri uri = new Uri("daipp://...");
bool success = await Launcher.LaunchUriAsync(uri, options);

The uri format must follow the usual url rules or you’ll get a System.UriFormatException with “Invalid URI: The hostname could not be parsed” as a reason. For example
ProtocolInvalidFormat
will fail because there is no initial host name.

I’m using the command to be parsed by the activated application as the hostname:
ProtocolUriFormat
The parameters are then passed as value pairs with the same format as a query string. Spaces are supported but values and parameter names should not contain the ‘=’ character.

In the DA case, the Process.Start method activates the associated application:
Process p = Process.Start(string.Format("saipp://{0}", answer));

Unfortunately, the returned Process instance is always null… Does it means that it is impossible to figure out if something went wrong? Not always. You know when the WSA associated with the protocol does not start fast enough because a Win32Exception is thrown by Process.Start.
ExceptionWhenWSADoesNotStartQuicklyEnough

For other weird errors such as crashes in the activated WSA, another WinException will be thrown but this time with a remote procedure call failure.
ExceptionWhenWSACrashes

If you want to test a protocol, simply use the Run dialog box that pops up when you hit WIN+R.
RunWeatherProtocol

When you type the bingweather protocol, guess what? The Windows Weather WSA will be activated! This is the basics to build shortcuts to well-known installed Windows WSA and read this post for more détails.

How to associate an application to a custom protocol?

As with file extension, a WSA registers a protocol in its manifest via the Déclarations section
WSAProtocolDeclarationManifest

Without any surprise, a DA registers a custom protocol in the Registry under HKEY_CLASSES_ROOT and the protocol name
DAProtocolRegistryAssociation
The default value of the “command” subkey points to the command line to execute.

How to handle application activation?

When a WSA gets activated, the OnActivated override of its Application-derived class is called. The received IActivatedEventArgs parameter provides an ActivationKind information via the Kind property with Protocol as value. In that particular case, the argument should be cast into ProtocolActivatedEventArgs to access the expected Uri
ProtocolActivatedEventArgs
This Uri type comes from WinRT, not from the BCL.

The WIN+R Run dialog box helps you to test your uri values
ProtocolWithSPACE
In that case, the received Uri looks like the following under the debugger:
UriUnderDebugger

The Host and LocaPath properties are your friends because they have been url-decoded, unlike the AbsolutePath and AbsoluteUri properties. There is a gotcha if the uri is not well-formed: when you try to access the Uri property of the activation argument override, a System.UriFormatException is raised without any chance to get access to the original string uri. Even worse, as explained in MSDN, this exception is not available for WSA. As a consequence, you need to catch the base class FormatException to detect such a case.

For a DA, the uri is passed via the command line
DAProtocolActivationUri
without any need to uri-decode the string. The Environment.CommandLine property starts with the process pathname surrounded by quotes followed by a space and the protocol query string.

Use a query string Luke!

The two commands the DA provides via the custom protocol will start a DA like Notepad.exe or activate a WSA. As the previous examples have shown, the best way to define you’re a protocol is to use a query string-based syntax. Unlike Bing Map, it won’t be too complicated because only a few parameters are needed.

Activate a WSA from a DA

ActivateCommandDescription
This code is first checking if the given WSA identity is installed on the machine by leveraging the PackageManager type exposed by WinRT. This code has already been detailed in one of my posts where I described how to call WinRT API from a DA.

The WinRT API can’t help for the activation part but, hopefully, the Windows SDK exposes in ShObjIdl.h the signatures and GUID necessary to activate a WSA as described in http://msdn.microsoft.com/en-us/library/windows/desktop/hh706902(v=vs.85).aspx.

The complicated part is to build the first parameter of the ApplicationActivationManager.ActivateApplication method. We are lucky that the Package returned by the WinRT PackageManager provides exactly what we need as shown in the following code:
ActivateWSAwithWinRT

Start a DA from a DA

StartCommandDescription
This one is very easy to implement thanks to the Process.Start method method that accepts the executable as a parameter.

Download source code for WSA and DA

The next and last post of the series will discuss advanced communication scenario such as silent communication, without switching the user between the Modern UI world and the Desktop world.

This entry was posted in .NET, C#, Metro, Store App, WinRT and tagged , , , , , . Bookmark the permalink.

6 Responses to Inter-Process communication with protocol association in WinRT – Part 3

  1. Pingback: Windows Store Developer Links – 2013-04-16 | Dan Rigby

  2. Great article! But I have a little problem… everything worked as expected for untill today… the WSA fires the launchUriAsync but the DSA does not catches that event… everything in my registry is as expected, did not change anything… do you anything about that kind of behavior all of the sudden?
    Regards

    • Hi Sebastian,
      I don’t have an immediate explanation for this king of magical change: usually something has been updated to trigger this behavior modification. The DSA should be started by Windows: did you try the url via the Run dialog?
      What you can do is to check in the Control Panel (see the détails in the previous post) if the protocol is still well defined. You could also remove the definition by hand in the Registry (sorry but I did not think about providing the code for that cleanup) and redo the registration as an Admin. It is also possible that another App has been registered to the same protocol: you should detect it in the Control Panel.
      Are you using my sample or have you built your own version?
      I hope this helps.

      • Thanks Christophe, I got it running again by exporting the registry, deleting the entry to my protocol and adding it back again 😦
        I have no idea what happened but it is now working again! Thanks

  3. Pingback: Inter-Process Silent Communication in WinRT – Part 4 | Anything about WinRT

Leave a reply to Christophe Nasarre Cancel reply