DeutschEnglish

Aug 31

Retrieving the Windows OS version #3

For those who are not fully satisfied with the Interop solutions presented in the first two parts of this series of articles, I’d like to present an alternative solution for retrieving the Windows OS version number that uses a totally different approach:

As part of an HTTP request to a server, every web browser sends its user agent. Essentially, this is a string that contains information about browser version, rendering engine, and – the underlying operating system! We can take advantage of this by (temporarily) creating a WebView within out Windows Store App, and try to read the user agent that this WebView is storing internally, ready to send it to any web server.

In JavaScript, a browser’s user agent can be accessed through the navigator.userAgent property. We navigate the WebView to an empty HTML page, and then use the WebView’s InvokeScript method to run the JavaScript function eval(navigator.userAgent) that should return the full user agent value, and parse this string value to retrieve the OS version number.

The GetOSVersion() method can be used in the same way as the methods presented in the first two articles, as it returns the internal Windows version number (e.g., 6.3 for Windows 8.1). For a complete list of Windows versions and the internal numbering pattern, see this Wikipedia article. Since navigating to an HTML page and calling a JavaScript function invokes a separate task, the resulting method is asynchronous.

public async Task<string> GetOSVersion()
{
	string html = "<html />";
	string before = "Windows NT ";
	string after = ";";
	var task = new TaskCompletionSource<string>();

	var webView = new WebView();
	webView.LoadCompleted += (sender, args) =>
	{
		string info = webView.InvokeScript("eval", new[] { "navigator.userAgent" });
		task.TrySetResult(info);
	};
	webView.NavigateToString(html);

	string fullInfo = await task.Task;
	int start = fullInfo.IndexOf(before) + before.Length;
	int length = fullInfo.IndexOf(after, start) - start;
	string version = fullInfo.Substring(start, length);
	return version;
}

Please be aware that this is not production-ready code. When using this approach in any real-life App, be sure to take a look at the full user agent string, and adapt especially the parsing algorithm to be as robust as possible, including proper exception handling, making the code as safe as possible for future Windows versions.

Permanent link to this article: http://www.mobilemotion.eu/?p=1195&lang=en

Aug 27

Retrieving the Windows OS version #2

As discussed in Part #1, the GetVersionEx Interop function is not the best way for Windows 8.1+ Apps to retrieve the version of the operating system an App is currently running on. However, InteropServices also offers the VerifyVersionInfo function that can be used to achieve similar results.

Unfortunately, VerifyVersionInfo does not directly return the Windos version as it was designed to allow version comparisons, as for example to check if the currently used version is equal or greater than Windows 8.0.

With a simple wrapper function, this can be used to check several versions and retrieve the actual Windows version: The basic idea is to start with 6.2, which represents Windows 8.0, since this is the smallest version number Windows Store Apps can run on, and continuously incrementing both minor and major version number until the version comparison fails because the current version is not equal or greater than the tested one.

using System;
using System.Runtime.InteropServices;

public struct OsVersionInfoEx
{
	public uint OSVersionInfoSize;
	public uint MajorVersion;
	public uint MinorVersion;
	public uint BuildNumber;
	public uint PlatformId;
	public string CSDVersion;
	public ushort ServicePackMajor;
	public ushort ServicePackMinor;
	public ushort SuiteMask;
	public byte ProductType;
	public byte Reserved;
}

[DllImport("kernel32.dll")]
static extern ulong VerSetConditionMask(ulong dwlConditionMask, uint dwTypeBitMask, byte dwConditionMask);
[DllImport("kernel32.dll")]
static extern bool VerifyVersionInfo([In] ref OsVersionInfoEx lpVersionInfo, uint dwTypeMask, ulong dwlConditionMask);

private bool IsGreaterOrEqualOSVersion(uint majorVersion, uint minorVersion)
{
	var info = new OsVersionInfoEx();
	info.OSVersionInfoSize = (uint)Marshal.SizeOf(info);
	info.MajorVersion = majorVersion;
	info.MinorVersion = minorVersion;
	const uint verMinorversion = 0x0000001;
	const uint verMajorversion = 0x0000002;
	const byte verGreaterEqual = 3;
	const uint typeMask = verMajorversion | verMinorversion;
	ulong mask = VerSetConditionMask(
		VerSetConditionMask(0, verMajorversion, verGreaterEqual), 
		verMinorversion, verGreaterEqual);
	return VerifyVersionInfo(ref info, typeMask, mask);
}

public string GetOSVersion()
{
	string version = String.Empty;
	uint majorVersion = 6, minorVersion = 2;
	while (IsGreaterOrEqualOSVersion(majorVersion, minorVersion))
	{
		version = majorVersion + "." + minorVersion;
		if (minorVersion <= 9)
		{
			minorVersion++;
		}
		else
		{
			majorVersion++;
			minorVersion = 0;
		}
	}
	return version;
}

VerSetConditionMask can also be used to compare more detailed information such as the build number, but the major and minor version number should be sufficient to allow conclusions about the underlying Windows version, according to this list of version numbers.

This works for Windows 8.0 and 8.1 versions, but of course there is no guarantee that Microsoft will continue using the current versioning pattern, but it should not lead to problems in future versions. However, there is an alternative approach also that does not rely on Interop services, which wil be presented in Part #3 of this series of articles.

Permanent link to this article: http://www.mobilemotion.eu/?p=1191&lang=en

Aug 26

Retrieving the Windows OS version #1

A constantly recurring topic in most of my projects is the requirement of retrieving the operating system version a mobile App is running on. Since it’s not that easy to achieve this technically, the main aim of this (and the following) blog articles is to show some potential approaches and code snippets that can do the trick. But first let’s start with a theoretical question:

Why should I be interested in the OS version?

This is a highly controversial, widely discussed topic. On the one hand, one might be tempted to use detailed information about the underlying OS to offer or hide certain features to or from the user – such a requirement should rather be solved by either scanning for available sensors instead of OS version (for hardware related features) or providing distinct App versions for different OS versions in the store.

At the same time, OS version information can be extremely helpful: For example, when allowing users to send feedback or error reports, adding the exact OS version number might help to reproduce the reported issue. Another use case is statistics: Whenever an app shall send home statistical data about App usage, I recommend adding the OS version: This allows conclusions about the distribution of different OS versions among your customers, and can, for example, help with decisions about App version lifetime and backwards compatibility.

One word about Windows versions:

Speaking about Windows Store Apps (Modern Apps that run on Windows 8, 8.1, and hopefully also on future versions), it is important to know about the way Windows versions are encoded internally: Windows 8 is referred to as Windows NT 6.2, Windows 8.1 as Windows NT 6.3 – for a complete list, ask Wikipedia. When discussing functions that return the currently used system’s version number, these functions will usually return those internal version numbers.

How to do it? A first try:

The first thought might concern the GetVersionEx function. On Windows 8 Apps, you could do something like:

using System;
using System.Runtime.InteropServices;

public struct OSVersionInfoEx
{
	public uint OSVersionInfoSize;
	public uint MajorVersion;
	public uint MinorVersion;
	public uint BuildNumber;
	public uint PlatformId;
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
	public string CSDVersion;
	public ushort ServicePackMajor;
	public ushort ServicePackMinor;
	public ushort SuiteMask;
	public byte ProductType;
	public byte Reserved;
}

[DllImport("kernel32.dll")]
public static extern bool GetVersionEx(ref OSVersionInfoEx lpVersionInfo);

public string GetOSVersion()
{
	string result = String.Empty;
	var info = new OSVersionInfoEx();
	info.OSVersionInfoSize = (uint) Marshal.SizeOf(info);
	bool success = GetVersionEx(ref info);
	if (success)
		result = info.MajorVersion + "." + info.MinorVersion;
	return result;
}

Calling the GetOSVersion() method would then return 6.2, meaning Windows 8.0. What’s dangerous about this approach: Still works on Windows 8.1, but:

  • it’s unclear if the function will be available in future Windows versions, and
  • the function returns the OS version the App is manifested for, not the OS version that is currently being used

according to MSDN.

This might still be the way to go for certain specific use cases, but for most applications we’re looking for a general solution to simply retrieve the running OS version. For a detailed example of such an alternative approach using InteropServices, please refer to Part #2 of this series of articles.

Permanent link to this article: http://www.mobilemotion.eu/?p=1190&lang=en

Aug 07

Large geometric shapes appearing blurred in WinRT

The short story:

When drawing large geometric objects in a Windows Store App, the edges appear blurred.

The long story:

When drawing a dashed, horizontal line with a width of, for example, 1000, everything works fine:

<Line X1="50" Y1="50" X2="1000" Y2="50" Stroke="White" StrokeThickness="6" StrokeDashArray="4,2" />

What you see when running the App should be similar to the following image:

Short line
 
 

Now change the line’s width to, let’s say, 9000, and run it again (of course this only makes sense within some kind of ScrollViewer or a similar container unless you use a really large screen, but I’ve omitted this part as it doesn’t change the point I’d like to demonstrate):

<Line X1="50" Y1="50" X2="9000" Y2="50" Stroke="White" StrokeThickness="6" StrokeDashArray="4,2" />

Long line
 
 

Wondering where these blurred edges come from, since the geometry itself didn’t change? The reason is that WinRT draws geometric object pixel by pixel only until a maximum size of 2048×2048. If some object is larger than that, it simply gets scaled like an image – you can imagine that simple upscaling doesn’t produce the nicest results. It seems that this is not due to a bug but done on purpose for performance reasons, although I don’t see how this could improve the overall performance, since the only solution seems to be to split up the geometric object into several shapes, each not larger than 2048 units horizontally and vertically.

Permanent link to this article: http://www.mobilemotion.eu/?p=1182&lang=en

Aug 01

ArgumentExceptions when scheduling tile updates

The short story:

Scheduled tile notifications in WinRT allow planning tile updates to be executed in the future. However, always double-check that the scheduled point in time really is in the future, otherwise you might be presented with a potentially misleading exception in the best case (or, for example, a silently faling background task when scheduling the tile update from within there…)

The long story:

Recently, one of my App projects failed at a pretty inconspicuous line of code: The ScheduledTileNotification constructor was throwing an ArgumentException pointing to a “wrong argument” in the constructor call:

var plannedTime = DateTime.Now.AddSeconds(5);
// some more calculations and variable assignments
var scheduledNotification = new ScheduledTileNotification(tileDocument, new DateTimeOffset(plannedTime));

I first checked the passed tileDocument but its XML structure was both tidy and according to the Tile Template Catalog. Finally it turned out that the second argument was to blame: In some cases, all the calculations made between declaring the planned timestamp and actually scheduling the notification took more than 5 seconds, resulting in an already elapsed timestamp being passed to the ScheduledTileNotification constructor! Of course, this can’t work out, but I’d vote for a more verbose exception message to point an unprepared developer like me into the right direction…

Ok, now that the reason for the exception was identified, I moved the declaration of plannedTime down to the line directly before the call to ScheduledTileNotification(...) and gave it another try, this time stepping through each line of code using the debugger and looking at all values in detail. Same behavior as before: ArgumentException thrown in some cases! I have to admit that it was my fault this time: If more than 5 seconds passed before hitting the Step over button to reach the constructor calling line, the timestamp is in the past again… should have figured that before!

Lessons learned:

Sounds simple, but in the future I’ll always double-check timestamps before passing them to a scheduled tile notification. This is especially important if the scenario illustrated above takes place within a background task’s code, because in this case you won’t be notified about the exception, instead the background task will just crash silently and the tile update is never gonna happen!

Permanent link to this article: http://www.mobilemotion.eu/?p=1178&lang=en

Jul 24

Automatic color adaptation to background brightness

Imagine in one of your projects (no matter if Phone, Store, or even Desktop = WPF) you’ve got some status to be displayed in a TextBox. There might be an enumeration like this

enum Status {
	Running,
	Warning,
	Error,
	Failure
}

The text could then be bound to some property of this Status type, and in addition you might want to bind the TextBox’s Background to the same property via a StatusToBrushConverter, in order to signal the status in a traffic-light-like color scheme. Now the text has four states that will look similar to the folloing four images:

Without ColorContrastConverter
 
 

Nice, but shouldn’t also the text’s foreground color adapt in order to be readable even on the darker background colors? Of course you could write another converter that defines the best foreground color for each value within the enumeration, but in this case you’d need to change both converters each time the enumeration changes.

Instead, I suggest setting the foreground color to black or white depending on the background’s brightness. How to achieve that in an automatic way? Let me introduce the ColorContrastConverter!

The idea is to analyze the background color (which we know, because it is explicitly set by an existing converter), and return either black or white, depending on whether the background color is lighter or darker than average. Put this logic into a ValueConverter, use the background color and this new coverter as the text’s Foreground property’s binding target, and we’re done! And the best thing: This converter is totally reusable in the next App project.

Okay, let’s take a look at the code (the following snippet shows the code for Windows Store Apps, for Phone or WPF you’d need to adapt the Convert and ConvertBack methods’ signatures accordingly):

public class ColorContrastConverter : IValueConverter
{
	public object Convert(object value, Type targetType, object parameter, string language)
	{
		if (value is SolidColorBrush)
		{
			var color = (value as SolidColorBrush).Color;
			const double threshold = (3*255)/2;
			int sum = color.R + color.G + color.B;
			return new SolidColorBrush(sum > threshold ? Colors.Black : Colors.White);
		}
		return DependencyProperty.UnsetValue;
	}

	public object ConvertBack(object value, Type targetType, object parameter, string language)
	{
		return DependencyProperty.UnsetValue;
	}
}

To enable direct binding, the converter expects and returns SolidColorBrush objects, however for internal calculation the brushes Color property is used.

The color value consists of three channels representing the red, green, and blue components. Each of the three channels can contain a numeric value from 0 to 255, so the color’s total value can range from 0 to 3 * 255 = 765. The threshold between defining a color as “light” or “dark” is between these values, at 765 / 2 = 382.5. If the actual color value is below this threshold, the background color is “dark” and we return white as foreground color, since this is the lightest possible color. Otherwise the background color is “light” and therefore we use black as foreground color.

Of course, this is just a simple example and you might adapt this algorithm to your needs, e.g. to take into accont transparent backgrounds by incorporating the color’s alpha value.

To use this converter in any XAML page, we first need to register it as resource:

<Page.Resources>
	<converters:ColorContrastConverter x:Key="ColorContrastConverter" />
</Page.Resources>

Now we’re ready to use it! Simply bind the TextBox’s Foreground to its own Background property via this new converter:

<TextBox Text="{Binding MyStatus}" Background="{Binding MyStatus, Converter={StaticResource StatusToBrushConverter}}" 
	Foreground="{Binding RelativeSource={RelativeSource Self}, Path=Background, Converter={StaticResource ColorContrastConverter}}" />

Now the foreground color is automatically adapting to the background’s brightness:

With ColorContrastConverter
 
 

In practice however, you’ll want the status field not to be editable, for example by using a TextBlock instead of the TextBlox. Unfortunately, the TextBlock control does not provide a Background property… Instead, we could wrap it inside a Border, then the ColorContrastConverter binding needs to reference the Border’s background color:

<Border x:Name="StatusBorder" Background="{Binding MyStatus, Converter={StaticResource StatusToBrushConverter}}">
	<TextBlock Text="{Binding MyStatus}"
		Foreground="{Binding ElementName=StatusBorder, Path=Background, Converter={StaticResource ColorContrastConverter}}" />
</Border>

Of course, an even tidier solution would be referencing the border via a RelativeSource binding instead of naming it. Since this is solved quite differently on the WPF, Store, and Phone platforms, refer to my older blog post Mastering RelativeSource Bindings: TemplatedParent as alternative to FindAncestor!

Permanent link to this article: http://www.mobilemotion.eu/?p=1098&lang=en

Jul 23

MVVMbasics 1.4 includes converters

The latest version of the MVVMbasics framework 1.4 now comes with a basic set of four value converters to be used in custom views! Both the framework itself and an updated version of the Visual Studio templates are now available for download.                                        

Permanent link to this article: http://mvvmbasics.mobilemotion.eu

Jul 19

Localizing a Store App’s manifest

The short story:

A few months ago, I wrote a series of blog posts concerning internationalization and localization of Windows Phone and Windows Store (and cross-platform) Apps, that explain the use of resource files to include culture-specific string values in both C# code and XAML markup. This article shows, how to localize entries within a Windows Store’s appxmanifest file.

The long story:

In addition to labels, caption, etc. within your code, you might want to add localized content to the App’s manifest also. For example, the App’s Display name and Description but also the Package display name and in some cases also the Publisher display name should appear in each user’s local language. This can be achieved using the ms-resource keyword.

Most of the text fields presented in Visual Studio’s visual manifest editor can be filled with the ms-resource: prefix, followed by a key that is defined in the global resource file. The following image shows an example:

Localized manifest file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

However, in contrast to resource references from within XAML or C# code, the given key must be defined within a *.resw resource file, *.resx files are not supported.

If the App is pure Windows Store project (without Portable Class Libraries targeting different platforms), it might be useful to completely switch to the *.resw file format and only use one type of resource file. To add such a file to the project, select the Resources file (.resw) option from Visual Studio’s Add New Item wizard. Filling the file with key-value-pairs works the same way as with *.resx files.

One important difference between the two file types is that *.resw resource files must be positioned within a folder that encodes the language and/or culture of the contained resource file. (When using *.resx files, this is done by adding a language-code prefix to the filename itself.) For example, when supporting English, German, and French languages, there should be three folders, each containing one resources file with the same name, as illustrated in the following picture:

Resource files
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

When working on a Store project that is part of a cross-platform solution, resource files already exist on the Portable Class Library layer, in order to be shared by all contained projects. In this case, new *.resw files must be created directly within the Store project as described above, but they need only contain those key-value-pairs that are referenced within the appxmanifest.xml file. All other values that are used from within C# or XAML code can stay in the existing, old resource files.

Permanent link to this article: http://www.mobilemotion.eu/?p=1113&lang=en

Jul 11

Magically moving pushpins on a Bing map

The short story:

Always remember that images added as overlay pushpins to a Bing maps control have their bound location at the upper left corner!

The long story:

Let’s imagine you have a Windows Store App that includes a Bing maps control, and you’d like to add pushpins that contain a custom image to certain locations on the map. If your pushpin icon looks similar to X, not a problem. If the pin’s tip points in another direction, it will slowly move away from its original position when zooming into the map…

The reason is that the upper right corner of the pushpin image is positioned at the exact GPS location as specified. If it was the image’s center, we could simply enlarge to image to four times its size with a transparen background and move the icon inside the image such that its tip points to the image’s exact center point.

Unfortunately this is not the case, and this results in the effect of a (seemingly) moving pin, because the upper left corner is fixed, but the viewer concentrates on another point of the image (the one the pin’s tip points to) – since the maps changes its size when zooming and the pin image doesn’t, this point moves further and further away from its original position…

What can we do about this problem (if always using pushpins that point in the upper left direction is not a suitable solution)?

Lessons learned:

The obvious solution is to move the pushpin image – I’d like to introduce two ways to achieve this, although there might exists a lot more options.

Option 1 is using a translation. Imagine the following existing code, and a pushpin image that looks similar to Pushpin:

<Page.Resources>
	<Style TargetType="bing:Pushpin" x:Key="PushpinStyle">
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="bing:Pushpin">
					<Image Source="../Assets/pin_red.png" Width="32" Height="32"/>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
</Page.Resources>

<bing:Map Credentials="YOUR_API_CODE">
	<bing:Map.Children>
		<bing:Pushpin Width="32" Height="32" Style="{StaticResource PushpinStyle}">
			<bing:MapLayer.Position>
				<bing:Location Latitude="{Binding Lat}" Longitude="{Binding Long}" />
			</bing:MapLayer.Position>
		</bing:Pushpin>
	</bing:Map.Children>
</bing:Map>

We simply add a transformation to the pushpin object that translates the image the same amount of pixels that correspond to the image’s height! So, let’s change the code as follows:

		<bing:Pushpin Width="32" Height="32" Style="{StaticResource PushpinStyle}">
			<bing:Pushpin.RenderTransform>
				<TranslateTransform Y="-32" />
			</bing:Pushpin.RenderTransform>
			<bing:MapLayer.Position>
				<bing:Location Latitude="{Binding Lat}" Longitude="{Binding Long}" />
			</bing:MapLayer.Position>
		</bing:Pushpin>

This snippet simply moves the image 32 pixels upwards (since the image is 32 pixels high), resulting in the lower left corner staying at the specified location!

Another option is to move the pushpin image through setting a margin. If we wanted to use a pushpin like this Cross, we’d need to move the image in two directions to bind its center point to the desired GPS location. In pratice, this look like the following:

<bing:Map Credentials="YOUR_API_CODE">
	<bing:Map.Children>
		<bing:Pushpin Width="32" Height="32" Style="{StaticResource PushpinStyle}" Margin="-16,-16,0,0">
			<bing:MapLayer.Position>
				<bing:Location Latitude="{Binding Lat}" Longitude="{Binding Long}" />
			</bing:MapLayer.Position>
		</bing:Pushpin>
	</bing:Map.Children>
</bing:Map>

In this example we’re moving the pushpin image 16 pixels up and 16 pixels to the left – done!

Permanent link to this article: http://www.mobilemotion.eu/?p=1093&lang=en

Jul 07

The People’s Swedish Dictionary

This new App provides a tablet-friendly, touch-optimized user interface for the Folkets lexikon web service that is available at http://folkets-lexikon.csc.kth.se/. It provides a simple dictionary for translations of English words to Swedish, and vice versa.

                                                                               

Permanent link to this article: http://www.mobilemotion.eu/?page_id=1124

Older posts «