Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Windows Mobile Widget 101 – A Gadget Side Note

As I’ve mentioned in a previous post it is quite easy to take your Windows Mobile widget and convert it into a Windows Vista/Windows 7 gadget. In this post I’ll take the Hello World widget I built in the Getting Started and Start Menu Icons posts and walk through converting it into a gadget.

Gadgets are almost identical in structure to widgets, with one exception. Instead of a config.xml manifest file, gadgets use a gadget.xml file. So, the first step in converting your widget is to add a gadget.xml file to your project. Here is a sample file that mirrors the information I used in the config.xml file for the widget.

-----------------
gadget.xml
-----------------

<?xml version="1.0" encoding="utf-8" ?>
<gadget>
  <name>Hello Gadget World</name>
  <namespace>
http://www.builttoroam.com/hellogadgetworld</namespace>
  <version>0.1.0.0</version>
  <author name="Built to Roam">
    <info url="
http://www.builttoroam.com" text="Built to Roam" />
    <logo src="icon.png" />
  </author>

  <copyright>Copyright (c) 2009 Built to Roam.  All rights reserved.</copyright>
  <description>This is a sample gadget that says Hi to the world!</description>
  <icons>
    <icon width="90" height="90" src="icon.png" />
  </icons>
  <hosts>
    <host name="sidebar">
      <base type="HTML" apiVersion="1.0.0" src="Main.htm" />
      <permissions>full</permissions>
      <platform minPlatformVersion="0.3" />
    </host>
  </hosts>
</gadget>

Of course, you now need to modify your build to include this file. Now you have two options here, you can either build a single compressed file and simply change the extension between .widget and .gadget depending how you want to use it. Alternatively you can make your build slightly more intelligent:

-----------------
Build.bat
-----------------

cd .\HelloWorld
del ..\helloworld.widget /Q
..\7za.exe a -tzip ..\helloworld.widget -r0 @..\files.txt
copy ..\helloworld.widget ..\helloworld.widget.zip

cd .\HelloWorld
del ..\helloworld.gadget /Q
..\7za.exe a -tzip ..\helloworld.gadget -r0 @..\gadget_files.txt
copy ..\helloworld.gadget ..\helloworld.gadget.zip
pause

This build file now makes use of a file called gadget_files.txt which contains the file specific to building the gadget (ie includes gadget.xml and not config.xml).

-----------------
gadget_files.txt
-----------------

gadget.xml
Main.htm
icon.png

You can now run the build batch and it will generate a .gadget file.  Double-click this file under Windows Vista or Windows 7 and it will install and run your gadget.  Unfortunately you’re likely to see something like the following:

image

This happens because the gadget dynamically sizes to fit the content, which means that if you don’t specify a height or width for the gadget you get very minimal space allocated to it. This is simply fixed by adding size information to the body tag of the Main.htm file.

<body style="height:200px;width:200px;border:1px solid #000000">

Now if you build and run (ie double-click on the gadget file) the gadget you will see the following:

image

And there you have it – your widget is running as a gadget.  Now there are some additional features of gadgets that we aren’t using here but I’ll come back to them as we get into adding more functionality to the widget.

Windows Mobile Widget 101 – Start Menu Icons

In my previous post on Getting Started with widgets I showed how easily you can create a Windows Mobile widget. However, what you would have noticed when you installed the widget is that it uses the default widget icon both during installation and on the start menu (see below). Whilst it’s not a bad icon, it doesn’t advertise your application or company brand. As such it’s recommended that you supply your own icon.

image image

 

To do this you need to supply an icon file in two formats. For Windows Mobile Professional devices (ie touch screens) you need to supply a 90x90 png image. For Windows Mobile standard you need to supply an ico file that includes images at 44x44, 22x22 at both 32 and 8 bit colour.

Here’s the step by step instructions for creating and including icons for your widget.

  • Start with a regular image and use a image editing tool to resize the image to 90x90.  I typically use Paint.NET which is a free tool that supports a wide range of image formats. If your image isn’t square you will need to crop/resize the image canvas to make it square.
  • With the image resized, simply save it as a png file, icon.png, into the same folder as you widget config.xml file.

Logo 90x90

(note that the black background indicates that the transparent area of the image – use transparency where possible so that you can see the background of the start menu behind your application icon)

  • Next, to build the ico file you will need to scale your icon to the different formats required to be contained within the ico file. For this I use another free tool, IcoFX.
    • Open IcoFX
    • Insert the original 90x90 image: File > Import Image, select your image, specify the size and resolution to import the image at.  I recommend importing the original at the original size (ie 90x90).  Doing this will not affect how it renders on the device since ico files can contain images at any resolution.

image

    • Next, add new images for each desired size and bit depth: Icon > New Image, specify size and bit depth.

image

    • Repeat for 44x44 32 bit, 44x44 8 bit, 22x22 32 bit, 22x22 8 bit.
    • Save the created ico as icon.ico in the same folder as your config.xml file.
  • The last thing to do is to update both the config.xml file and your build files list to include the icon files.

-----------------
config.xml
-----------------

<?xml version="1.0" encoding="utf-8" ?>
<widget xmlns="http://www.w3.org/ns/widgets"
        id="http://www.builttoroam.com/hellowidgetworld"
        version="0.1">
  <name>Hello Widget World</name>
  <icon src="icon.png" />
  <icon src="icon.ico" />
  <description>This is a sample widget that says Hi to the world!</description>
  <author href="http://www.builttoroam.com" email="[email protected]">
    Built to Roam Widget Development Team
  </author>
  <content src="Main.htm" type="text/html"/>
</widget>

-----------------
Files.txt
-----------------

config.xml
Main.htm
icon.ico
icon.png

Now when you run your build batch script and then install the widget on your device you will see your icon displayed both during installation and on the start menu.

image image

Notes:

1) The widget installation screen is not displayed during installation when the widget is downloaded from marketplace. As this is the only sanctioned way to distribute widgets to a Windows Mobile device you don’t need to worry too much about getting the installation screens perfect.

2) If you include both a png and ico file in your widget (and specified in the config.xml file) you will notice that no image is displayed during installation on Windows Mobile standard.  This is a known bug but given that this isn’t displayed to the end user (see 1 above) this shouldn’t be an issue.

Windows Mobile Widget 101 – Getting Started

Over the past month or so I’ve been working on a number of projects involving Windows Mobile Widgets.  If you aren’t familiar with widgets they are essentially a mini-application published as a zip file containing html, js, css and images.  They are similar to Windows Vista/7 gadgets; in fact so much so that you can use exactly the same code to produce both a widget and desktop gadget. In this post I’ll go through creating a basic widget, including a couple of tricks that can help you build and debug your widgets.

We will of course start off with the canonical Hello World widget and for the most part I’m going to be working in Visual Studio 2010.  That’s right, you can build and debug* your widgets from within Visual Studio 2010, which makes it the only form of Windows Mobile development you can currently do with the beta.

Let’s start by building up the necessary project structure for your widget. From the File menu, select New –> Web Site, then select the Empty Web Site project template from under either the C# or VB node.  Since you are going to be writing javascript it doesn’t matter what language you select. By default this will create a new project with just a web.config file – this file is not required for your Windows Mobile widget but does enable desktop debugging so leave it in the project. Next, add a new HTML document to your project (Add New Item –> C#/VB –> HTML Page).  I typically call this Main.htm as you normally only have a single htm page within your widget that contains all the markup for your widget but the name isn’t important. Modify the html to include a title and some content between the body tags.  For example:

<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title>Hello Widget</title>
   </head>
   <body>
      Hello Widget World!
   </body>
</html>

When you install your widget the installer needs to locate the main html page of your widget, along with other information about your widget such as the author, title and description of the widget.  This is located in a config.xml file. Add a new xml file called config.xml to your project (Add New Item –> C#/VB –> XML File) – the name of this file is important. Add, and then modify to suit yourself, the following to the config.xml file.

<?xml version="1.0" encoding="utf-8" ?>
<widget xmlns="
http://www.w3.org/ns/widgets"
        id="http://www.builttoroam.com/hellowidgetworld"
        version="0.1">
   <name>Hello Widget World</name>
   <description>This is a sample widget that says Hi to the world!</description>
   <author href="
http://www.builttoroam.com" email="[email protected]">
      Built to Roam Widget Development Team
   </author>
   <content src="Main.htm" type="text/html"/>
</widget>

You now have the minimum requirements for a Windows Mobile widget. If you press F5 to run this project in Visual Studio you will see the Main.htm web page display (if not, you may have to navigate to this page, or Set [it] as Start Page. To run your widget on a device (or emulator) there are a few more steps involved.

The first thing you need to do is to actually zip up your widget project into a .widget file.  This is essentially just a zip file, renamed with the .widget extension. As you don’t want to be doing this manually every time you make a change I created a simple batch file (yeh I know, super old school) that simply calls 7zip (free download) to zip up the relevant files.

-----------------
Build.bat
-----------------

cd .\HelloWorld
del ..\helloworld.widget /Q
..\7za.exe a -tzip ..\helloworld.widget -r0 @..\files.txt
copy ..\helloworld.widget ..\helloworld.widget.zip
pause

Place this batch file in the parent folder of your Hello World widget – you don’t want to mess up your project folder with build files.  You need to download and copy the 7zip executable into this folder and you need to create a file called files.txt – this contains a list of files to include in your widget.

-----------------
Files.txt
-----------------

config.xml
Main.htm

Running this batch file will create two output files: helloworld.widget and helloworld.widget.zip.  The former is a .widget file that you can copy to your device and click on to install.  The latter is created just in case you want to inspect the zip file to ensure all the right files are being packaged – there is nothing worse than trying to track down a javascript issue, only to discover one of the files isn’t being correctly added to the package.

Ok, so down to business, lets get this widget to run on the emulator/device.  If you are using an emulator then you can simply cradle the emulator using WMDC, copy the file across to the device using File Explorer and then click on the copied file to run the widget installer.  This will automatically run the widget when installation is complete.  If you want to run your widget on a real device there are some additional steps. By default the widget installer is not associated with the .widget file extension.  In order to get your widget to install by clicking on it, you need to create this association by modifying the registry on the device to include the following values:

[HKEY_CLASSES_ROOT\riapp] "EditFlags"=dword:00010000

[HKEY_CLASSES_ROOT\riapp\Shell\Open\Command] @="wmwidgetinstaller.exe %1"

You can do this using either Remote Registry Editor (external tool that ships with Visual Studio 2008), Pocket Controller PC or another third party registry editing tool.  Note that on most devices the HKEY_CLASSES_ROOT\riapp key already exists but the HKEY_CLASSES_ROOT\riapp\Shell\Open\Command key will need to be created.  Also note that the @ in the second line corresponds to the “default” value for the key – this means that depending on your editing tool you should either leave the name component empty or use the word Default.

Once you have added these registry keys to your device, clicking on the .widget file should run the installer – if not, it is likely that the registry keys are not correct, or that the wmwidgetinstaller.exe executable can’t be located. Again, once installation is complete your widget should automatically run displaying similar to the following:

image

Note that the Title in the Main.htm file is used to populate the widget title bar and that the default Exit button and menu has been created.

Creating your first widget is as simple as that. In fact you could submit this widget, in its current form to Windows Mobile Marketplace as it conforms to all the necessary requirements for certification.

 

 

*Build and Debug is limited to desktop debugging only. You still need to deploy to an emulator and/or a real device in order to ensure your widget is going to work correctly.

New Windows Mobile build with Zooming

In my continual quest to get more performance and better experience out of my HTC Touch Pro device (given the HTC WM6.1 performs so badly) I decided to give the latest build off XDA-developers a go.  The following is taken from build 23504 which you can grab from the following link http://forum.xda-developers.com/showthread.php?t=580429. The main reason I wanted to upgrade was not so much for the improvements to the experience (since I’ve already seen some massive improvements over the last couple of builds), it was more to get some of the performance benefits that has been touted in the latest builds.

Now, unlike some of the other images available, this particular build is very vanilla in nature.  It doesn’t include Touch Flo 3D, so it looks for the most part like Windows Mobile 6.5. One thing I did have to do was to change the keyboard configuration to match the Touch Pro.  This is done with the following registry setting:

HKLM\HARDWARE\DEVICEMAP\KEYBD\CWSLayout to 0 (then restart)

The build does indeed appear to perform better.  Navigation seems to be very responsive but this may be that it doesn’t have the overhead of the TouchFlo. 

Now if you look at the first of the following images you will see that there is a rendering issue around the clock.  This only seems to be on the today screen and as you can see in the second image, if you click in the notification area you get a set of expanded icons.  The expanded notification bar is in full colour and has gesture support to allow you to easily scroll through the icons. 

What caught my attention was the Zoom icon. Clicking on this zooms the current screen in (see third image).  This is an awesome feature of this rom image as it allows you to zoom in on nearly anything that is rendered on the screen. Better yet, you can still interact with the contents of the screen whilst zoomed in – the fourth image shows the Getting Started page which is what is loaded when you click the icon in image 3.

image image

imageimage

Good and Bad news about WCF for Windows Mobile

Given this post primarily contains a rant about WCF support within the .NET Compact Framework (ie Windows Mobile), I’ll start with the good points.

  • Further to a previous post on WCF for Windows Mobile the team at Microsoft have released an updated version of NetCFSvcUtil.exe that fixes the issue running under Vista SP2 and Windows 7.  You can download it directly from their blog post on the NetCFSvcUtil QFE (great way to ship updates – an obscure blog that no-on.
  • There is a great whitepaper put together by a couple of MVPs talking about using WCF from the .NET Compact Framework: http://wcfguidanceformobile.codeplex.com/.

Ok, so now for the bad news.

  • If you’re thinking about using Basic Authentication, you can forget WCF.  There is no support for nearly any practical scenario for using WCF unless you want to roll out X509 certificates.  Honestly, whoever didn’t think that Basic Auth over SSL would be good to support…..
  • If you want to share types between client and server, think again. It appears that the /reference and /excludeType flags don’t work as they do with svcutil.exe which means a lot of messing around if you want to share types.
  • No built in support within Visual Studio for doing “Add Service Reference”

If you’re like me and spend most of your time in Visual Studio the last point is a real kick in the head – you mean I have to run NetCFSvcUtil from the commandline, Urgh!  At this point I went “forget it – too hard, too broken, not worth the pain” and went back to “Add Web Reference” (which btw works for WCF endpoints that are configured with basicHttpBinding).  This works well with both basic authentication and SSL so suits my scenario.

Now the issue I have with “Add Web Reference” is that it does silly things with certain types.  For example Guids get converted to string.  It also means that if you have two services (eg ServiceA.svc and ServiceB.svc that use the same type (eg Customer) you will end up with multiple types created on the client (eg ServiceA.Customer and ServiceB.Customer). The solution to this lies within the References.cs file that gets generated – this file contains all the types that get created as part of creating the proxy.  If you remove all the additional generated classes (eg ServiceA.Customer).  This will of course cause compile errors because the referenced types can’t be resolve.  To fix this, add a reference to the assembly that contains the type and then add a using statement to the reference.cs to import the missing types.

One last point - In order for this to work you will probably have to annotate your shared types with xml attributes. For example:

[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://myschemas/DataTransferObjects")]
public class Customer
{

I do wish that Microsoft would do something about the dire state of affair around WCF from .NET Compact Framework, but in the meantime I’d still with Add Web Reference.

Integrating Twitter into your Windows Mobile Widget

I guess the first question that comes to mind is why would you want to integrate twitter into your widget. Until recently I would have agreed that it seems somewhat superfluous as there is an almost infinite number of Twitter clients out there, all claiming that they are better than all that have gone before them. However, I was recently trying to add a mechanism for commenting on items within a widget I was writing.  Now I could have easily built yet another commenting system, involving the usual candidates of sql server backend, wrapped in a simple REST or SOAP service blah blah blah, but I came to the conclusion this would simply add to the overhead of managing the application, particularly since up until now the widget didn’t rely on any backend services. I figured since a lot of users would probably have Twitter accounts I could just let them use their account in order to make comments. The fact that their comments would be seen in their Twitter feed would just add some free advertising for my widget.

So, having chosen Twitter to handle comments I then had to work out the best way to integrate them. If you’ve used any of the current generation of Twitter clients out there you will be familiar with having to enter your username and password into the application – this is bad as you don’t really have any idea what else that application may be doing with your credentials. Of course, they would argue that they need to prompt for this information so that they can post on your behalf. Up until recently they would have been correct. However, Twitter now supports OAuth and in particular a permutation specifically designed to support desktop (or rich client) applications. In a nutshell this involves routing the user to Twitter, getting them to sign in there and then routing back to the calling application with a suitable authorisation token.  For the desktop permutation there is an additional step which involves copying a one-time pin from Twitter into the calling application – this is because there is no way for Twitter to redirect back to your desktop application. This process can be used for integrating Twitter into your widget.

Now for the technical bits:

Step 1: Registration

  • You need to register your application with Twitter.  This can be done at http://twitter.com/oauth_clients.  Once registered you will be given a Consumer Key and Consumer Secret that you will need to take note of for use within your widget.

Step 2: Request Token

  • The first step in OAuth is to get a request token.  This is done by issuing a POST to http://twitter.com/oauth/request_token, supplying the consumer key you have been allocated, a timestamp and nonce value. The request also needs to contain a SHA1 signature.
  • The return values (if successful) is a token and a token secret.

Step 3: Direct User to Twitter to Sign In

  • Once your widget has the request token and associated secret, you need to direct the user to Twitter.com so that they can log in and authorise your widget.  To do this, direct them to “http://twitter.com/oauth/authorize?oauth_token= + Token + & oauth_callback=oob"
  • The user will log in and then be given an authorisation pin.  They need to copy this and paste it (or type it) into your widget – you’ll need to give them a mechanism for doing this!

Step 4: Access Token

  • After the user has entered the authorisation pin you need to use it, coupled with the consumer key and request token to issue a POST to http://twitter.com/oauth/access_token.
  • This will return an access token that you can then use to post updates to Twitter.

Step 5: Post Updates

Acknowledgments to John Kristian who contributed a Javascript Library for OAuth.  Other OAuth libraries are available for a variety of languages at http://oauth.net/code.

Full TwitterAPI Listing

Feel free to use this code.  Note however that there is almost no error handling so that it’s easier to follow what’s going on.

var TwitterAPI = function() {
    return {
        ConsumerSecret: "<enter Consumer Secret from Twitter app registration>",
        ConsumerKey: "<enter Consumer Key from Twitter app registration>",
        SignatureMethod: "HMAC-SHA1",

        RegisterUser: function(callback, errorcallback) {

            var accessor = { consumerSecret: TwitterAPI.ConsumerSecret
                           , tokenSecret: ""
            };
            var message = { action: "
http://twitter.com/oauth/request_token"
                  , method: "POST"
                  , parameters: []
            };
            message.parameters.push(["oauth_consumer_key", TwitterAPI.ConsumerKey]);
            message.parameters.push(["oauth_signature_method", TwitterAPI.SignatureMethod]);
            message.parameters.push(["oauth_timestamp", ""]);
            message.parameters.push(["oauth_nonce", ""]);
            message.parameters.push(["oauth_signature", ""]);
            OAuth.setTimestampAndNonce(message);
            OAuth.SignatureMethod.sign(message, accessor);
            var parameterMap = OAuth.getParameterMap(message.parameters);

            var params = TwitterAPI.buildParameters(parameterMap);

            var request = WidgetAPI.createXmlHttpRequest();
            request.open(message.method, message.action, true);
            request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            request.setRequestHeader("Content-length", params.length);
            request.setRequestHeader("Connection", "close");

            // Set the callback
            request.onreadystatechange = function() {
                if (request.readyState == 4) {

                    var params2 = request.responseText.split("&");
                    for (var i = 0; i < params2.length; i++) {
                        var bits = params2[ i ].split("=");
                        if (bits.length == 2 && bits[0] == "oauth_token") {
                            TwitterAPI.Token = bits[1];
                        }
                        if (bits.length == 2 && bits[0] == "oauth_token_secret") {
                            TwitterAPI.TokenSecret = bits[1];
                        }
                    }

                    if (!TwitterAPI.Token || TwitterAPI.Token == null) {
                        if (errorcallback) {
                            errorcallback();
                        }
                        return;
                    }

                    callback();

                    var url = "http://twitter.com/oauth/authorize?oauth_token=" + TwitterAPI.Token + "&oauth_callback=oob";
                    window.open(url);
                    request = null;
                }
            };

            request.send(params);
        },
        AuthenticateUser: function(pin, callback, errorcallback) {
            TwitterAPI.Pin = pin;
            var accessor = { consumerSecret: TwitterAPI.ConsumerSecret
                           , tokenSecret: TwitterAPI.TokenSecret
            };
            var message = { action: "
http://twitter.com/oauth/access_token"
                  , method: "POST"
                  , parameters: []
            };
            message.parameters.push(["oauth_consumer_key", TwitterAPI.ConsumerKey]);
            message.parameters.push(["oauth_token", TwitterAPI.Token]);
            message.parameters.push(["oauth_signature_method", TwitterAPI.SignatureMethod]);
            message.parameters.push(["oauth_verifier", TwitterAPI.Pin]);
            message.parameters.push(["oauth_timestamp", ""]);
            message.parameters.push(["oauth_nonce", ""]);
            message.parameters.push(["oauth_signature", ""]);
            OAuth.setTimestampAndNonce(message);
            OAuth.SignatureMethod.sign(message, accessor);
            var parameterMap = OAuth.getParameterMap(message.parameters);

            var params = TwitterAPI.buildParameters(parameterMap);

            var request = WidgetAPI.createXmlHttpRequest();
            request.open(message.method, message.action, true);
            request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            request.setRequestHeader("Content-length", params.length);
            request.setRequestHeader("Connection", "close");

            // Set the callback
            request.onreadystatechange = function() {
                if (request.readyState == 4) {
                    var params2 = request.responseText.split("&");
                    for (var i = 0; i < params2.length; i++) {
                        var bits = params2[ i ].split("=");
                        if (bits.length == 2 && bits[0] == "oauth_token") {
                            TwitterAPI.Token = bits[1];
                        }
                        if (bits.length == 2 && bits[0] == "oauth_token_secret") {
                            TwitterAPI.TokenSecret = bits[1];
                        }
                    }

                    if (params2<2 || !TwitterAPI.Token || TwitterAPI.Token == null) {
                        errorcallback();
                        return;
                    }

                    callback();
                }
            };

            request.send(params);
        },
        PostComment: function(comment, callback, errorcallback) {
            accessor = { consumerSecret: TwitterAPI.ConsumerSecret
                   , tokenSecret: TwitterAPI.TokenSecret
            };
            message = { action: "
http://twitter.com/statuses/update.json"
          , method: "POST"
          , parameters: []
            };
            message.parameters.push(["oauth_consumer_key", TwitterAPI.ConsumerKey]);
            message.parameters.push(["oauth_token", TwitterAPI.Token]);
            message.parameters.push(["status", comment]);
            message.parameters.push(["oauth_version", "1.0"]);
            message.parameters.push(["oauth_signature_method", TwitterAPI.SignatureMethod]);
            message.parameters.push(["oauth_timestamp", ""]);
            message.parameters.push(["oauth_nonce", ""]);
            message.parameters.push(["oauth_signature", ""]);

            accessor.tokenSecret = TwitterAPI.TokenSecret;
            OAuth.setTimestampAndNonce(message);
            OAuth.SignatureMethod.sign(message, accessor);
            var parameterMap = OAuth.getParameterMap(message.parameters);

            message.action = "http://twitter.com/statuses/update.json";
            params = TwitterAPI.buildParameters(parameterMap);
            //params += "&status=test";
            request = WidgetAPI.createXmlHttpRequest();
            request.open(message.method, message.action, true);
            request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            request.setRequestHeader("Content-length", params.length);
            //request.setRequestHeader("Connection", "close");

            // Set the callback
            request.onreadystatechange = function() {
                if (request.readyState == 4) {
                    callback();
                }
            }
            request.send(params);
        },
        buildParameters: function(parameterMap) {
            var params = "";
            for (var p in parameterMap) {
                if (params.length > 0) {
                    params += "&";
                }
                params += OAuth.percentEncode(p) + "=" + OAuth.percentEncode(parameterMap[p]) + "";
            }
            return params;
        }
    };
} ();

var Url = {

    // public method for url encoding
    encode: function(string) {
        return escape(this._utf8_encode(string));
    },

    // public method for url decoding
    decode: function(string) {
        return this._utf8_decode(unescape(string));
    },

    // private method for UTF-8 encoding
    _utf8_encode: function(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // private method for UTF-8 decoding
    _utf8_decode: function(utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while (i < utftext.length) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if ((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

}

More Windows Mobile 6.5 builds

Well almost on the eve of the public availability of Windows Mobile 6.5 I thought I’d again post about some of the new builds that I’ve been using. Over the past week or so I’ve been running build 53052 and today I’ve upgraded to build 53420. There aren’t any huge improvements over my previous post however the polish is really starting to show.  In fact over the past week or so I would confidently say that I wouldn’t consider moving away from Windows Mobile and that for my day to day life it’s easier to use than an iphone. Anyhow, here are a few screenshots showing the polish as it continues to improve:

image image

imageimage

image image

Windows Azure, .NET Services from a Windows Mobile Widget

[This post is based on the Windows Azure Tools for Microsoft Visual Studio July 2009 CTP]

That’s right, if you hadn’t guessed what I was working on with my previous posts on .NET Services (Tokens, Queues I, II, III, Routers I & II) I’ve been working towards accessing .NET Services from within a widget. I must apologise for the following as it’s just a code dump of a sample widget that shows how to create a queue and subscribe to an existing router.  Note that if you are going to use this on a number of devices you need to create a unique queue on each device, otherwise you’ll end up subscribing to the router multiple times – this will cause duplicate messages in your queue and contention between the devices dequeuing the messages.

To get this widget to work, simply create a widget (Developing Widgets for Windows Mobile 6.5) and then copy the following code into your html file.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml" >
<head>
    <title>Widget Chat</title>

      <script type="text/javascript">
          var theToken;
          var theRouter = "myrouter"
          var widgetQueue = "widget";

          function connect() {
              var solutionName = document.getElementById("SolutionNameText");
              var solutionPassword = document.getElementById("SolutionPasswordText");

              alert('Solution Name: ' + solutionName.value);
              alert('Solution Password: ' + solutionPassword.value);
              httpGetAuthenticationToken(solutionName.value, solutionPassword.value, createQueue);
          }

          function createQueue() {
              alert('Creating Queue');
              httpCreateQueue(theToken, widgetQueue, subscribeToRouter);
          }

          function subscribeToRouter() {
              alert('Subscribing to Router');
              httpSubscribeQueueToRouter(theToken, theRouter, widgetQueue, pollForMessage);
          }

          function pollForMessage() {
              httpDequeueMessage(theToken, widgetQueue, messageReceived, pollForMessage);
          }

          function messageReceived(message) {
              alert('Message Received: ' + message);
              pollForMessage();
          }

          function send() {
              var messageBox = document.getElementById("Message");
              httpRouteMessage(theToken, theRouter, messageBox.value);
          }

          function httpGetAuthenticationToken(username, password, callback) {
              try {
                  http = new XMLHttpRequest();
                  http.open("GET", "
https://accesscontrol.windows.net/IssueToken.aspx?u=" + username + "&p=" + password);
                  http.onreadystatechange = function() {
                      if (http.readyState == 4) {
                          if (http.status == 200) {
                              theToken = http.responseText;
                              alert('Authenticated:' + theToken);
                              callback();
                          }
                          else {
                              alert('Authentication failed');
                          }
                      }
                  }
                  http.send();
              }
              catch (e) {
                  alert(e.message);
              }
          }

          function httpCreateQueue(token, queue, callback) {
              var policy = "<entry xmlns=\"
http://www.w3.org/2005/Atom\">" +
  "<QueuePolicy xmlns=\"
http://schemas.microsoft.com/netservices/2009/05/servicebus/connect\">" +
    "<ExpirationInstant>2009-09-03T01:00:00.0000000Z</ExpirationInstant>" +
  "</QueuePolicy>" +
"</entry>";

              http = new XMLHttpRequest();
              http.open("POST", "
https://blogsample.servicebus.windows.net/" + queue, false);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.setRequestHeader("Content-type", "application/atom+xml;type=entry;charset=utf-8");
              http.onreadystatechange = function() {
                  if (http.readyState == 4) {
                      if (http.status == 201) {
                          var created = http.responseText;
                          alert('queue created: ' + created);

                      }
                      else {
                          alert('queue not created - ' + http.status);
                      }
                      callback();
                  }
              }
              http.send(policy);
          }

          function httpGetServiceList(token) {
              http = new XMLHttpRequest();
              http.open("GET", "
https://blogsample.servicebus.windows.net/", false);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.onreadystatechange = function() {
                  if (http.readyState == 4 && http.status == 200) {
                      output = http.responseText;
                      alert(output);
                      // Do something with the service list
                      httpRenewQueue(token, "mobilequeue", output);
                  }
              }
              http.send();
          }

          function httpRenewQueue(token, queue, getResponse) {
              xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
              xmlDoc.async = "false";
              xmlDoc.loadXML(getResponse);

              var entry;
              var entries = xmlDoc.getElementsByTagName("title");
              var i;
              for (i = 0; i < entries.length; i++) {
                  if (entries[ i ].childNodes[0].nodeValue == queue) {
                      entry = entries[ i ].parentNode;
                  }
              }
              entry.getElementsByTagName("ExpirationInstant")[0].childNodes[0].nodeValue = "2009-08-31T09:56:25.2951184Z";

              http = new XMLHttpRequest();
              http.open("PUT", "
https://blogsample.servicebus.windows.net/" + queue + "/!(queue)", false);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.setRequestHeader("Content-type", "application/atom+xml;type=entry;charset=utf-8");
              http.onreadystatechange = function() {
                  if (http.readyState == 4 && http.status == 200) {
                      var output = http.responseText;
                      alert('renew: ' + output);
                      httpEnqueueMessage(token, queue, "Hi Everyone");
                  }
              }
              http.send(entry.xml);
          }

          function httpDeleteQueue(token, queue) {
              http = new XMLHttpRequest();
              http.open("DELETE", "
https://blogsample.servicebus.windows.net/" + queue + "/!(queue)", false);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.onreadystatechange = function() {
                  if (http.readyState == 4 && http.status == 200) {
                      var deleted = http.responseText;
                      alert('deleted');
                  }
              }
              http.send();
          }

          function httpEnqueueMessage(token, queue, message) {
              http = new XMLHttpRequest();
              http.open("POST", "
https://blogsample.servicebus.windows.net/" + queue, false);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.setRequestHeader("Content-type", "text/plain;charset=utf-8");
              http.onreadystatechange = function() {
                  if (http.readyState == 4 && http.status == 202) {
                      var output = http.responseText;
                      alert('enqueue: ' + output)
                      httpDequeueMessage(token, queue);
                  }
              }
              http.send(message);
          }

          function httpDequeueMessage(token, queue, callback, noMessageCallback) {
              http = new XMLHttpRequest();
              http.open("DELETE", "
https://blogsample.servicebus.windows.net/" + queue + "/!(queue/head)?encoding=asreply&maxmessages=1&timeout=30", true);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.onreadystatechange = function() {
                  if (http.readyState == 4) {
                      if (http.status == 200) {
                          var output = http.responseText;
                          callback(output);
                      }
                      else {
                          noMessageCallback();
                      }
                  }
              }
              http.send();
          }

          function httpRouteMessage(token, router, message) {
              http = new XMLHttpRequest();
              http.open("POST", "
https://blogsample.servicebus.windows.net/" + router, false);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.setRequestHeader("Content-type", "text/plain;charset=utf-8");
              http.onreadystatechange = function() {
                  if (http.readyState == 4) {
                      if (http.status == 202) {
                          var output = http.responseText;
                          alert('Send ok!');

                      }
                      else {
                          alert('Unable to send');
                      }
                  }
              }
              http.send(message);
          }

          function httpSubscribeQueueToRouter(token, router, queue, callback) {
              var policy = "<entry xmlns=\"
http://www.w3.org/2005/Atom\">" +
              "<link rel='alternate' href='
https://blogsample.servicebus.windows.net/" + queue + "' />" +
  "<HttpHeaders xmlns=\"
http://schemas.microsoft.com/netservices/2009/05/servicebus/connect\">" +
    "<HttpHeader name='X-MS-Identity-Token' value='" + token + "' />" +
  "</HttpHeaders>" +
"</entry>";

              http = new XMLHttpRequest();
              http.open("POST", "
https://blogsample.servicebus.windows.net/" + router + "/!(router/subscriptions)", false);
              http.setRequestHeader("X-MS-Identity-Token", token);
              http.setRequestHeader("Content-type", "application/atom+xml;type=entry;charset=utf-8");
              http.onreadystatechange = function() {
                  if (http.readyState == 4) {
                      if (http.status == 200) {
                          var created = http.responseText;
                          alert('subscribed ok:' + created);
                          callback();
                      }
                      else {
                          alert('not subscribed ok' + http.status);
                      }
                  }
              }
              http.send(policy);
          }

      </script>
</head>
<body>
    <p>   
    Solution Name:<br />
    <input id="SolutionNameText" type="text" />
        <br />
    Solution Password:<br />
    <input id="SolutionPasswordText" type="password" /><br />
    <Button onclick="connect()">Connect</Button>
    </p>

    <p>   
    Message:
        <br />
    <input id="Message" type="text" /><br />
    <Button onclick="send()">Send</Button>
    </p>

</body>
</html>

New Builds of Windows Mobile 6.5

Earlier this week I noticed a post on MoDaCo talking about newer builds of Windows Mobile 6.5.  By newer, I’m of course comparing the builds to what’s publically available in the emulator images as part of the Windows Mobile 6.5 Developer Toolkit. As I’m currently wielding a HTC Touch Pro device (which for the record was one of the worst purchase decisions I’ve made due to the lack of support from both Expansys Australia and HTC) I figured I’d take a look at some of the xda-developer roms that they’ve been cooking with the latest Windows Mobile 6.5 bits.  Here are just a few screen shots from the NATF_WM6.5_TP_Lite_v5.5A ROM

Disclaimer: Please note I would NOT recommend trying cooked roms as they have the potential to brick your device – do so at your own peril. This post is just to highlight some of the new functionality that we may be expecting in production WM6.5 devices later this year.

image image

1) Notification bar – you will notice that the notification area at the top of the screen is a little smaller than before. It’s also missing the start icon.  Clicking any where in the notification area will show an enlarged notification bar (second image) where you can then click on the icon you actually want to access.

2) Start – this is no longer in the notification area, appearing instead in the SIP/Menu bar at the bottom of the screen.  This is applied throughout the device, not just the today screen.

image

3) Ok – this has also been moved out of the notification area and placed in the SIP/menu bar.

4) Gestures for Tabs –gesturing left and right navigates between tabs.

image

5) Slide Tabs – instead of tabs appearing at the bottom of the screen, they now appear as “previous and next” headings at the top of the screen.  You can use left and right gestures anywhere on the form to navigate to previous or next tabs. Note that they are cyclic so you can keep going “next” (or “previous”) to go repeatedly through all the tabs – imho not particularly intuitive as there’s no indication of what all the tabs are and how to jump straight to a specific tab.

image image

6) Start Menu – instead of the “Move to Top” option you got when you click and hold on an icon in the start menu.  Now when you click and hold you can drag the icon around the start menu to change the layout to suit you. Unfortunately you don’t seem to be able to add/remove folders, nor drop an icon into a folder.

Now I’m sure there are other new features that I haven’t come across but these are the ones that after 20secs caught my eyes.

Windows Mobile Widget (lack of) Security

I have to preface this post by saying that Windows Mobile Widgets run under the same context as Internet Explorer Mobile on a Windows Mobile 6.5. This means that in terms of securing data across the wire you should use HTTPS/SSL over any connection you wish to send usernames, passwords and other sensitive data. What I want to cover in this post is some information on how to protect the security of your data sources.

Windows Mobile Widgets are great for visualising existing web data sources.  By this I mean that instead of relying on users browsing to your website on their mobile device, you can build a widget that mashes up rss, web service and other data to build a rich local user experience. Unfortunately, if you only want your data sources to be consumed by the widget you build there are a couple of things you should be aware of:

  • Widgets are just plain text html files with or without javascript, which is also plain text – this means that any thing you put in a widget can easily be extracted.  Sure, you can obfuscate the javascript code, but essentially any usernames, passwords or keys will be able to be decoded.
  • Once a widget is installed on the device it is possible for anyone with physical access to the device to extract the widget files. This means that any user who downloads and installs your widget from the Marketplace will be able to connect to their device and view (and in fact edit) the widget files. [This is assumed based on the behaviour of the Windows Mobile 6.5 emulator and may be different with an RTM build of Windows Mobile where they may work out how to protect widget files]
  • With access to the usernames, passwords or keys from your widget files any developer will be able to create their own widget that accesses your data sources without your permission.

Ok, so I mentioned something about protecting your data sources…. well, here is a proposed strategy for ensuring your data is only accessed by your widget running on a Windows Mobile device:

  • If you look at the headers for a request coming from a widget you will notice a couple of things:
    • Referer: x-widget1:///\\Program%20Files\\Widgets\\User\\2\\Products.htm
      • The \Program Files\Widgets\User\2\Products.htm is the name of the file on the Windows Mobile device that is loaded into the widget. Widgets get installed into the \Program Files\Widgets\User folder by expanding .widget zip file onto the device.
    • User-Agent: WMWidgets 1.0 (MSIE6.0;Windows CE;http://www.builttoroam.com/ProductWidget)
      • The agent string “WMWidgets 1.0” confirms that this request is coming from a Windows Mobile device, whilst the “http://www.builttoroam.com/ProductWidget” is the id of my widget defined within the config.xml file eg:
      • <?xml version="1.0" encoding="utf-8" ?>
        <widget xmlns="
        http://www.w3.org/ns/widgets"
                id="http://www.builttoroam.com/ProductWidget"
                version="1.0">

  • You can make use of this header information in two ways.
    1. The first, and probably simpler, way is to verify these headers as part of the call to your data source. This is the easiest way if you own and are able to change the way that the data sources work.
    2. If you can’t modify the data source and they take a username, password or key to access them, then you need to protect these pieces of information. Do not insert them into the widget html or javascript itself (as outlined above they are very easy to extract off the device). Instead build a simple web service that will return the required username, password or key upon request.  As part of the request you would of course verify the headers to ensure it is coming from your widget running on a Windows Mobile device.

This sounds all very well but what’s to stop someone from getting my widget, copying the code into their own widget and using the same id and/or filenames. Well the answer to this is that I’m assuming that the id specified in the config.xml file will be unique on the Windows Mobile Marketplace [yet to be confirmed by Microsoft but that would seem logical since there needs to be a way in Marketplace to uniquely identify your widget]. This would mean that another party can’t create a widget using your id and upload it to Marketplace.

But what’s to stop someone from creating a widget with the same id and publishing it on their website. The answer is that there is nothing to stop them from doing that. However, no non-cracked Windows Mobile device will be able to install that widget – Windows Mobile Marketplace is the only way to install widgets on a non-cracked Windows Mobile 6.5 device. On the Windows Mobile 6.5 emulators, you can simply copy a .widget file onto the device and then install it by clicking on it in File Explorer on the device. This is not possible on a non-cracked Windows Mobile device as the file extension .widget is not recognised by the device (By setting the following registry keys will enable this feature on your device and thus “cracking” your device: [HKEY_CLASSES_ROOT\riapp] "EditFlags"=dword:00010000,  [HKEY_CLASSES_ROOT\riapp\Shell\Open\Command] @="wmwidgetinstaller.exe %1").

Why is the HTML version in Windows Mobile 6.5 in 4.01 and Not 5?

One of the questions asked at the Sydney Windows Mobile Debug Day was what version of HTML does Windows Mobile 6.5 Internet Explorer Mobile, and subsequently Widgets, support? The answer is that IE Mobile 6 supports HTML v4.01 (as well as javascript 5.7). This received a bit of debate since the Palm Pre offers support for HTML 5 and as such wouldn’t Microsoft want to future proof their platform.

I think one thing to remember is that most OEMs who build and sell Windows Mobile phones do not offer regular or frequent updates to the ROMs, and unlike some platforms, Microsoft is unable to push out updates when they make changes to the core platform.  Why is this relevant? Well, if you are across the HTML standards you will know that HTML 4.01 is “a stable document and may be used as reference material or cited as a normative reference from another document” (from the W3C HTML 4.01 Specification), where as the HTML 5 “specification is not stable” (from the W3C HTML 5 Specification) and they further state:

Implementors who are not taking part in the discussions are likely to find the specification changing out from under them in incompatible ways. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation stage should join the aforementioned mailing lists and take part in the discussions.

Whilst I’m sure that Microsoft has representation on the appropriate committees/lists, I would suggest that it is a little presumptuous to implement HTML 5 on a device that is no easily updatable. I guess we can only hope that the HTML 5 specification is locked down in time for the next version of Windows Mobile.

Adding Maps to your Windows Mobile Widget

One of the questions that came up at the Windows Mobile Debug Days (part of the Codemasons’ Guild) was how to integrate mapping into your application.  This prompted me to experiment with integrating the Bing Map (javascript) Control into a Windows Mobile Widget.  Whilst the javascript engine in Windows Mobile 6.5 has been given a massive injection of life, I was very skeptical that the javascript control would work out of the box. I was proven wrong with the map working with no modifications.  The following code is taken out of the online visual sdk, with the only change being the height and width of the map div to fit into the widget.

<html>
   <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <script type="text/javascript" src="
http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
      <script type="text/javascript">
          var map = null;

          function GetMap() {
              map = new VEMap('myMap');
              map.LoadMap();
          }  
      </script>
   </head>
   <body onload="GetMap();">
      <div id='myMap' style="position:relative; width:240px; height:260px;"></div>
   </body>
</html>

The only issues I found with the javascript control relate to the gesture support within the widgets in Windows Mobile 6.5. When you pan your finger within a widget it attempts to scroll the widget itself.  Unfortunately this means that you can pan the map by dragging your finger across the map.  Instead you have to use the navigation control in the top left corner.

clip_image002

Windows Mobile Happenings

This post covers a number of “happenings” in the Windows Mobile space, so I’ll start with a list:

Wow, what a list.  Well let’s start at the top…

Codemasons’ Guild

The Codemasons’ Guild is the brainchild of the Australian Windows Mobile team.  These guys rock; at a time where I’m continually astounded by the lack of action from Microsoft in the Windows Mobile space, the action that’s coming out of the Australian team is inspiring!  Anyhow, back on topic…. the Guild is a local Australian portal for developers interested in building applications for Windows Mobile.  The idea is that by bringing together some industry names (James, Rog, Nick, Dave, and myself), partners in the Windows Mobile space, events and a forum, we can build a local community that will foster a whole industry around device applications.

Jumpstart Series

Next on the list is the Jumpstart series.  This is actually a sub-item of the Codemasons’ Guild as all the information about this series is available via the Guild website. To date there have been three sessions:

  1. Session 1: View the recorded introduction session to Windows Mobile 6.5 and Marketplace
  2. Session 2: Getting started developing for Windows Mobile 6.5
  3. Session 3: Widgets: the new Internet Application (recording not yet available)

At this stage the team is looking at how this series can be continued.  If you have any topic that you would especially like to be covered, please let one of the WinMo Oz team know.

Marketplace

The Windows Mobile Marketplace has opened for application submissions, including the Race To Market challenge. You should definitely take a read of the following documents to get ready for submitting your application to marketplace.

Note that in order to submit your application you will need to register ($99 US/$150AUD); you will then have to wait for your digital certificate from GeoTrust for application signing.  The upshot – don’t assume you’ll be able to sign up and submit in one sitting.

Debug Days

Next week the Australian Windows Mobile team, coupled with the team from the Guild are hosting three Debug Days. Well, they’re actually evenings – from 4:30pm through to around 9pm we’ll be helping you with any issues you may have in designing, building, debugging, deploying….. or anything else related to Windows Mobile development.  The idea is that you can either let us know before hand, or just rock up and surprise us, with anything you want help with.  This is going to be a fully interactive session – the more thinking/prep you do before hand, the more value you’ll get out of the session.

Anyhow, the registration links are now open and I look forward to catching up with as many of you as possible next week:

Competitions

As if I haven’t covered enough, there are a bunch of competitions you can enter related to WM6.5 and Marketplace:

Sign up now and get your mobile application on the shelves of Windows Marketplace for Mobile. When you submit your app, you’ll also be eligible to win the Race to Market Challenge and exciting prizes, including:

  • A Microsoft Surface table
  • Online marketing and promotion
  • A one-of-a-kind trophy

Ready for the challenge?

For developers - do you have a clever concept for a Windows® phone application? We’d like to help you turn it into a best-seller on Windows Marketplace for Mobile. Interested? Simply submit your brilliant concept by August 21, 2009 and you could win one of three prize packs worth $5,000 each! You can enter as many times as you like, as long as each entry is different.

The each of the 3 prizes includes a fully paid ticket to TechEd Australia on the Gold Coast (with 3 nights accom & flights).  The 3 prize winners will have their app showcased at TechEd, including at Smackdown – where we will judge the Master Codemason Application.

Are you a Student? Got a great idea for a mobile app but no way to make it happen? Submit your idea by August 17, 2009 and you could win one of two developer mentorships and share in prizes! You can enter as many times as you like, as long as each entry is different

SDNUG

If you didn’t see the Livemeeting last week on Windows Mobile 6.5 and Widgets, I’m doing a session at the Sydney Deep .NET User Group tomorrow evening.  Full details:

SDNUG Double Header:

Web and application access: supporting the needs of people with disabilities by Dr Scott Hollier

WM6.5, Widgets and Marketplace by me :-)

Thursday 6 Aug 2009 6.00pm - 8.00pm (add to calendar)

Speed Up Your Windows Mobile Builds

One of the things that continually frustrates me about building Windows Mobile applications in Visual Studio is that for some reason it takes so long to do a build. Behind the scenes there is a lot that goes on and I always forget that there is one part of the build that you can mostly do without, the platform verification.  As pointed out by the now quite old post by the Visual Studio for Devices team you can disable this part of the build quite easily:

1) Open the file %windir%\Microsoft.NET\Framework\v2.0.50727\Microsoft.CompactFramework.Common.Targets for editing.

2) Go to the line which reads:
Name="PlatformVerificationTask">
and change it to:
Name="PlatformVerificationTask" Condition="'$(SkipPlatformVerification)' != 'true'">

3) Add the SkipPlatformVerification environment variable to the system and set it to "true" (To re-enable Platform Verification set the environment variable to "false")

4) Restart Visual Studio for the changes to take effect (If building from the command line using MSBuild, add /p:SkipPlatformVerification=true to your command line to turn off the task. You can specify the variable in the project file also, so that this information is persisted across sessions).

As noted by Thomas you may just want to disable this functionality, instead of having it contingent on an environment variable.  In this case just change the PlatformVerificationTask line to:

Name="PlatformVerificationTask" Condition="false">

Doing this you should notice that your mobile projects build just as fast as other projects within Visual Studio.  Note: This is still relevant in Visual Studio 2008 with SP1.

WCF on Windows Mobile and .NET Compact Framework

I was just listening to Don, Dave and James on the second of the Jumpstart series for the Codemasons’ Guild and the topic of communicating via WCF came up.  Now typically when I build mobile apps I don’t go through all the pain of using WCF, I simply use a regular asmx web service and then use Add Web Reference to add it to my mobile project.  To secure it, I just communicate over SSL. If you do want/need to use WCF on the server side, there are a couple of options to do this.

Before we jump into how you use WCF, let me point out a couple of useful powertoys:

The Power Toys for .NET CF include NetCFSvcUtil.exe which is a device equivalent of SvcUtil.exe and is needed in order generate the WCF proxy.

Firstly, you need to be aware that the .NET CF has some severe limitations when it comes to WCF.  Unfortunately the only binding that is supported (excluding the much over-hyped WCF via Exchange) is basicHttpBinding. For the WCF service you want to consume you need to change it from using the default wsHttpBinding.  This can be done by launching the Tools > WCF Service Configuration Editor from Visual Studio. Open the web.config file for the WCF Service project.  Under Endpoints, adjust the Binding to basicHttpBinding.

image

Save this change and run the WCF Service.

Now to the options…..

1) The first option is to use Add Web Reference.  This is by far the simplest approach as you can click Browse to: Web services in this solution.  Select your service and click Add Reference. 

image

Once you have added the reference you can call your service method the same way you would from a regular desktop application:

localhost.Service1 service = new localhost.Service1();
service.Url = service.Url.Replace("localhost", "192.168.1.2");
return service.GetData(5, true);

Note: You have to change the “localhost” host name to something that can be resolved by the device.  I typically just use the ip address of the development machine.  Clearly for production you will want to specify this in a configuration file or make it a configurable setting within your application.

2) The second option is to use NetCFSvcUtil.exe to generate the appropriate WCF proxy information. Start by opening up the Visual Studio command prompt (Start > Microsoft Visual Studio 2008 > Visual Studio Tools > Visual Studio 2008 Command Prompt) and adding the path to the Compact Framework power toys:

>> set path=%path%;C:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\bin

Navigate to the folder where you want the proxy files to be created and then use NetCFSvcUtil.  I figured this would be quite simple but it appears that somewhere between Vista SP1 and SP2 (and there are reports of this problem on Windows 7 too) a bug in NETCFSvcUtil surfaced preventing it from working.

image

As you can see the error message is really helpful:

Error: An error occurred in the tool.
Error: Error in the application.

Currently, there doesn’t seem to be a workaround for this.  Some people have had varied success by changing the parameters and return types of the service methods.  The one strategy I used that appears to work is to use a combination of SvcUtil and NetCFSvcUtil.

>> svcutil.exe c:\temp\WindowsMobileServices\MyDataServices\bin\MyDataServices.dll

Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation.  All rights reserved.

Generating metadata files...
C:\temp\WindowsMobileServices\WindowsMobileServices\tempuri.org.wsdl
C:\temp\WindowsMobileServices\WindowsMobileServices\tempuri.org.xsd
C:\temp\WindowsMobileServices\WindowsMobileServices\schemas.microsoft.com.2003.1
0.Serialization.xsd

>> netcfsvcutil.exe tempuri.org.wsd tempuri.org.xsd
Microsoft (R) .NET Compact Framework Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.5.0.0]
Copyright (c) Microsoft Corporation.  All rights reserved.

Generating files...
C:\temp\WindowsMobileServices\WindowsMobileServices\tempuri.org.cs
C:\temp\WindowsMobileServices\WindowsMobileServices\CFClientBase.cs

Now, include all the generated file into your mobile project.  You will also need to add references to System.ServiceModel and System.Runtime.Serialization.

In order to call your service method you can now write the following:

var binding = System.ServiceModel.BasicHttpBinding();
var endpoint = System.ServiceModel.EndpointAddress("http://192.168.1.2:6323/Service1.svc");
Service1Client client = new Service1Client(new binding, new endpoint
);
return client.GetData(5);

So, the question is why would you go the second option?  Well if you actually look at the generated code, adding the WCF service using Add Web Reference adds a bunch of unnecessary fields.  When calling the method GetData there is a second parameter called “valueSpecified” which is little more than a flag to indicate if the first parameter was specified or not.  This is not required if you use the second option to generate the proxy information.

Late Notice: Windows Mobile Jumpstart #2

Jumpstart #2:

Getting started developing for Windows Mobile 6.5: developer tools, technologies, debugging and testing
Learn how to get started developing for Windows Mobile 6.5, what can be done with the new technologies and how to use your existing skills to start coding apps for Windows Mobile 6.5 phones via Windows Marketplace.
Register for the second Live Meeting

Date/Time: Friday, July 17 (today!!), 2009 1:00 PM Australia (East)

 

And so that you’re ready for the next session:

Jumpstart #3

Widgets: the new internet application
Get insight into the Widgets platform for Windows Mobile 6.5 and discover how to develop powerful Widgets that leverage today’s web experience in a new way.
Register for the third Live Meeting

Date/Time: Friday, 31 July 2009 12:30 PM Australia (East)

Codemasons’ Guild for Windows Mobile Developer

Don has just posted some of the Q&A from last weeks jumpstart Live Meeting session.  I had a brief listen to the recorded session as I wasn’t able to attend the event and it provides a good roundup of what’s included in Windows Mobile 6.5 and the Marketplace.  The one question that I love, and we’ll hear again and again, is the following:

Q: If the application is available for free? what will Microsoft charge developer?

A: It will be charged as one of your signings

Microsoft’s stance on this one appears to be that there is a cost associated with signing and verifying your application.  Whilst they are prepared to cover 5 of these included in your registration for marketplace, there after you’re on your own, even for free applications. Unlike the iPhone where you have to use the AppStore to distribute your application, with Windows Mobile you can at least make the cab file available as a download from your website.  My suggestion is that if you are going to build free applications for Windows Mobile, build a simple application that provides an catalogue of all your free applications and provides a mechanism for downloading them.  Add this application to marketplace (using only 1 of your free apps) and there after just post your free applications to your blog, website etc and update the catalogue.

Oh, and the other question I love is:

Q: Is this a once off fees ?

A: 99 USD charge fee for 5 app signings

This answer is actually incorrect.  It’s $150 AUD!!! Why they can’t use the current exchange rate I don’t know but $150 is way too much imho for signing up to this service (For comparison, the AppStore I think was $115 AUD).

Repost: Windows Mobile 6.5 developer training – Jumpstart series

image

Friday, July 3, at 1pm (Sydney time) is the first of a series of 3 Live Meetings to help Australian developers get started developing for Windows Mobile 6.5 – and to get those apps in Marketplace (Windows Marketplace for Mobile – Open for Developer registration) to distribute/sell to the millions of Windows Mobile users globally.

These Live Meetings will run through July, all on a Friday starting at 1pm. So grab some lunch, your favourite beverage, and get ready to learn. The first starts Friday week, July 3 – click to register now.


July 3rd 1pm - Introduction to Windows Mobile 6.5 and Marketplace: the opportunity and the platform
This webcast introduces the new and upcoming features of Windows Mobile 6.5 and Windows Marketplace. It also outlines the incredible business opportunity for developers to reach millions of users globally via Windows Marketplace – and the processes required to do so.
Register now for Live Meeting session 1


July 17 1pm - Getting started developing for Windows Mobile 6.5: developer tools, technologies, debugging and testing
Learn how to get started developing for Windows Mobile 6.5, what can be done with the new technologies and how to use your existing skills to start coding apps for Windows Mobile 6.5 phones via Windows Marketplace.


July 30 1pm - Widgets: the new internet application
Get insight into the Widgets platform for Windows Mobile 6.5 and discover how to develop powerful Widgets that leverage today’s web experience in a new way.

Reposted on behalf of Don Kerr and the Australian Windows Mobile team [original post: http://blogs.msdn.com/wmoz/archive/2009/06/25/windows-mobile-6-5-developer-training-jumpstart-series.aspx]