# Tuesday, March 06, 2012

I just got an email in the Support inbox over at OpenNETCF asking about the libraries support (or really lack thereof) for Wireless Networking in Windows Embedded Compact 7 (rolls off the tongue, doesn’t it?).  While this is a question about a specific feature of the SDF, it really opens up the broader question of what our plans are for the future of the whole product.  In fact you could say it really opens up the question on what our general company plans and philosophy are.

First, let’s address this specific issue, as it deserves answering and has a little bit of a back story leading to a minor rant which is always fun. 

The SDF supports an object model for wireless networks that is based around the Wireless Zero Config (WZC) API.  Microsoft introduced WZC in CE 5.0 (IIRC) in an attempt to “standardize” the way the platform and apps would communicate with the wireless drivers, since NDIS doesn’t really have any specification for a lot of the wireless properties.  While I applaud the spirit, WZC is convoluted at best, and was definitely not designed to make the life of someone who has to use P/Invoke to communicate with it any easier.  Still, it was some sort of standardization so we rolled up our sleeves and created a managed interface for it. 

I’ll readily admit that what we ended with isn’t ideal, but I’m a fierce self critic and I rarely think what we do is as good as it could be.  Still it provided a programmatic interface for something that a *lot* of people wanted and that Microsoft had not implemented in managed code.

Well with Compact 7 (I’ll just call it CE7) Microsoft decided that WZC wasn’t the way to go, but instead Native WiFi was.  Painfully they didn’t follow a sensible “deprecated but supported” track for WZC and support side-by-side, they just dropped WZC support altogether.  That meant that we could not interface with a wireless adapter under CE7 using our existing code base at all – it was a flat-out break.

To make things worse, Microsoft went radio-silent for about 2 years (and still counting – yes I’m looking at you Redmond!) on what, if any, future the Compact Framework, or CE for that matter, might have.  The original WZC work was probably 4-6 weeks of development and it required that we buy several devices for testing.  Believe me, it was a real pain in the ass.  Do we (more specifically do *I*) really feel like doing that all again for the Native WiFi interfaces?  If I do, where do I get a CE7 device with WiFi support?  If I do all of that work, what’s the ROI if Microsoft kills the Compact Framework?  What’s the ROI if they revive it and implement Wireless themselves?

It’s really difficult to answer those questions, and we’re not the only ones who are wondering these things.  I can say, though, that we’ve very recently decided that yes, we will continue to do both support and new development for the SDF.  What that new development will entail I can’t say.  Not because it’s some big secret, but because I can’t make those plans until Microsoft tells us their plans (and they haven’t).  If they decide to release a new version of the Compact Framework, I’d like to not have a load of functionality duplication between it and the SDF.

So, is the SDF a dead product?  No.  We will continue to support it and have plans for feature additions.  We just don’t know exactly what those features will be or when they will be written (confidence inspiring, I know). 

Will we provide Wireless support for CE7?  If Microsoft does not, then yes, we will.  Again, we don’t know if they will or not.  If they did, we don’t know when that would be.  Ideally, though, programming for WZC and Native WiFi should be the same, so if they don’t do it, we’ll add support that looks and feels just like what’s in the SDF today.  If they do add it, I’d be inclined to update our object model to match theirs (keeping the old stuff for compatibility though).

Don’t read too much into this.  Yes, I’m optimistic about the Compact Framework and Windows CE Windows Embedded Compact but I’ve been using them for over a decade and I’ve based a whole lot of my knowledge, business and life on them.  I almost have to be optimistic.  But let’s face it, CE and the CF are still great tools for delivering products.  We’re still shipping products based on them.  Still doing new development and new installs.  Still writing proposals for them. 

Yes, we’ve tested the waters with Android and iOS.  We’ve even delivered finished products for them both, but using those tolls only reinforced my feelings about the strength and possibilities of the CF and CE and we’re still committed to using and supporting them.

Tuesday, March 06, 2012 5:25:57 PM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, November 01, 2011

This post is part of my "Software Development" series. The TOC for the entire series can be found here.


In this post, we’re going to look, at a higher level, at the reasons for and benefits of using a framework for Inversion of Control (IoC), Dependency Injection (DI) and Service Location. I’m not going to spend a large amount of time in this blog series describing the intimate details of what IoC, DI and Service Locators are.  Martin Fowler did a fantastic job of it and there’s no point in me just regurgitating his work.

Instead, I’ll give my vision of what they are and how they are relevant to how I architect and develop solutions.  It’s important to note that I’m starting out this series with high-level thoughts about architecture and design.  I’m not just laying down some code, leaving the decisions about how things will interact to some arbitrary, organic process.  This is how software development gets done. 

You’ve got to think about not just the next step, but visualize the end point several months, or even years out and try to connect the dots back to where you are today.  If I implement something in a certain way today, is it going to screw me 3 months down the road?  Spending an extra day now thinking about architecture is going to turn into saving weeks of the customer breathing down your neck and you pull out your hair and work late night trying to hammer a square peg into a round hole.

So let’s look at IoC, DI and Service Location and how they’re going to help us build better software.  Inversion of Control as a concept is something that’s really broad.  It’s really anything that turns the older procedural way of developing upside down (i.e. inverts program control, hence the name).  Moving from a console app to a windowed, event-driven app is technically inversion of control, so you’ve already been using IoC. 

To talk about IoC as a useful concept that’s actually going to be of use, we’ll be using some smaller units/principals of IoC.  The two we’re going to look at are Dependency Injection, or DI, and Service Location.  Neither one is complex or arcane, and you probably already use them to some degree.

Let’s assume we have two arbitrary classes, A and B, and that A uses an instance of B internally.  There are, essentially, 3 ways that A can get the instance of B. 

First, it can directly create it by calling new B().  While this is simple, it’s the least preferred, and generally worst, way to do it.  By directly creating B, A is now tightly coupled to B’s implementation.  B can’t be easily changed out to something else.  If B is in another assembly, A has to have a reference to it.  It’s also difficult to test A by itself. 

The second way that A can get B is that whoever created the instance of A could pass into it an instance of B.  Maybe through a constructor

var b = new B();
var a = new A(b);

or through a property

var b = new B(); 
var a = new A(); 
a.B = b;

This is called Dependency Injection. The former is constructor injection, the latter is property injection – not so complex, eh?  This is useful because, if B is an interface, it’s really easy to swap out the implementation passed to A and the assembly containing A doesn’t necessarily have to have a reference to the assembly holding the implementation of B – it only needs a reference to the interface.  This is really nice when we want to do mocking.

The third way that A can get B is to go get it from some central repository or “factory”.

B B { get; set; }

public A() 
{ 
   this.B = MyClassFactory.GetB(); 
}

This is service location.  A doesn’t really know what B is, it lets the service locator (MyClassFactory) resolve that.  This is really helpful for plug-in architectures as well as for lazy loading objects.

Generally speaking, your code should only be doing #2 (DI) and #3 (service location) for objects of any complexity.  This is not to say that you shouldn’t ever call the new operator in your code.  There’s obviously a grey line out there below which it would be pretty stupid to not just use new for.  If you need to use a simple entity class or structure, then creating one makes sense.  If you need access to the DAL and I see you creating a DAL object in your View, you’re fired.

There are plenty of framework out there that provide DI and service location -  Ninject, Unity, CastleWindsor, StructureMap, Autofac – the list goes on and on.  Instead of using one of them, however, I chose to roll my own.  Normally I wouldn’t recommend such a drastic action – after all reinventing the wheel isn’t usually wise – but in my case it was essentially required, so I’ll give you the short back story.

My team and I had been working on a large desktop application.  We had designed it from the start using Microsoft’s SCSF/CAB framework, which provide DI, service location and a load of other stuff.  It turned out that we were using maybe 10% of the framework, and that the framework’s Studio plug-ins were causing fits with some installations of Studio.  Spending time screwing with Studio plug-ins and trying to get things to compile is a terrible waste of manpower, so we were already getting close to jettisoning it when we decided that we wanted the core of our app logic to be Compact Framework compatible.

Well Microsoft’s “port” of the SCSF to the Compact Framework, called the MCSF, turns out to be a bloated, unbelievably slow, steaming pile of dog crap.  Side note: just because something compiles under the Compact Framework does not mean it should be used in the Compact Framework.  Well, I didn’t want to refactor everything we’d done to some other IoC framework, plus I couldn’t find one at the time that actually worked for the Compact Framework, so I decided to create one. 

I took the tack that I’d create it for the CF first, with a high emphasis on small footprint, minimal resource usage and speed and I simply matched the SCSF object model where our code base interfaced with it and where it made sense – in some places I didn’t like how the SCSF had done things, so I “fixed” their mistakes.  The end result was the OpenNETCF.IoC framework, which turns out to stack up quite well against the other frameworks.  It also has the huge benefit of working on the Full Framework, Windows Phone 7 and MonoTouch (probably MonoDroid as well, though I’ve not tested that). We’ll be looking at OpenNETCF.IoC in a lot more depth in this series.

Tuesday, November 01, 2011 9:50:17 AM (Central Standard Time, UTC-06:00)  #     | 
# Monday, October 31, 2011

This post is part of my "Software Development" series.  The TOC for the entire series can be found here.


Developing good software is hard.  Really hard.  Sure, anyone can buy a book on writing software or pull up some code samples and get something that compiles and runs, but that’s not’s really developing software.  A lot of code in the wild – I’d bet a vast majority of it – just plain sucks.

It’s hard to point out where the blame lies.  It seems that most developers are environmentally or institutionally destined to write bad code. Schools teach how to write code, but not how to architect it or to follow reasonable design practices.  In the zeal for clarity, publishers churn out books, blogs and samples that show bad practices (when is it ever a good idea to access a data model from your UI event handler?).  Managers and customers alike push hard to get things done now, not necessarily done right – only to find months or years later that doing it right would have saved a boatload of time and money.  And let’s face it – many developers are simply showing up to work to pull a paycheck.  You know who they are.  You’ve no doubt worked with them in the past.  You’re probably working with them now.

I was watching Gordon Ramsay the other day and it occurred to me that he and I are alike in our own peculiar way.  I’m not saying that I see myself as the “Gordon Ramsay of Software Development” – hardly -   but we share a common trait.  Just as Gordon gets angry and starts spewing colorful language when he walks into a crap kitchen, it bothers the hell out of me to see complete idiots in my chosen field out there just making a mess of things.  When I see bad code – not necessarily minor errors, or code that could be refactored and made better – but just outright shit code that should not have occurred to a developer in the first place it pisses me off.  By the nature of my work, often getting called in only when the project is off the rails, I see it all the time. Code that, on review, a peer or mentor should have seen and said “Whoa!  There’s no way that’s going into our code base”.  Code that just makes it harder for the next person to do their job.

In an effort to simplify things for my own code, for my customers’ code as well as anyone who is willing to listen to my ravings, I’ve spent a lot of time building, testing, fixing and extending tools and frameworks that many of which I turn around and give away.  This isn’t out of altruism, no, it’s largely because I’m a lazy developer.  I hate writing the same thing twice.  When I start a project, I don’t want to spend large amounts of time building up the same infrastructure that every project needs. Building up a framework for handling UI navigation isn’t what I’d call interesting, but just about every project needs it.  Handling object dependencies and events is common.  Writing a DAL for serializing and deserializing entities is not just drudgery, I find it’s highly susceptible to errors because you end up doing a lot of copy and paste.

I have these cool tools and frameworks that I use in literally every project I work on now.  That’s great for me, but it doesn’t really help others, right?  Without reasonable documentation or explanation, only a small handful of people are going to go through the effort of getting the tools and trying to understand them – even if they are deceptively simple and could potentially save you weeks of effort. 

So I’ve decided to put together a series of blogs over the coming weeks and months that explain, hopefully in simple terms, what these frameworks do, how to use them, and most importantly, why they are worth using.  There’s nothing groundbreaking here.  I didn’t invent some new way to do things.  I’ve simply appropriated other peoples’ ideas and extended them to work in the environments that I work.

Generally I’ll be covering the following topics and frameworks:

  • Dependency Injection and Inversion of Control (using OpenNETCF IoC)
  • Event Aggregation (using OpenNETCF IoC)
  • Plug-in Architectures and interface-based programming (using OpenNETCF IoC)
  • Software features as services (using OpenNETCF IoC)
  • Data Access through an ORM (using OpenNETCF ORM)
  • Parameter Checking (using OpenNETCF Extensions)
  • Exposing data services over HTTP (using Padarn)
  • Whatever else I think of

If there’s a topic you’d like me to talk about, feel free to send me an email.  I may turn on comments here and let you post ideas, but I find that when I enable comments on my blog, I start getting more comment spam than I really want to deal with, so if comments are turned off just drop me a line.

Monday, October 31, 2011 10:11:24 AM (Central Standard Time, UTC-06:00)  #     | 
# Friday, August 26, 2011

A recent question on StackOverflow got me sidetracked into the context menus for Windows CE/Windows Mobile.  The question is pretty simple - when you create a ContextMenu, it automatically "selects" the first item, and the OP wanted to know how to undo that selection.  I spent a few hours screwing around with reflection and trying to get at the handle for the menu items so I could P/Invoke and unselect the item and only ended up failing (though I did post the meat of my work in my original answer).

After doing that work it occurred to me that we (OpenNETCF) used to have a PopupMenu commercial control that we long ago pulled from our catalog.  Well I looked on our old source control server and sure enough, it was there.  Since it was doing no one any good sitting in a bit bucket, I added it to our published open-source control set over on Codeplex.

Friday, August 26, 2011 1:20:00 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, August 23, 2011

We've been heavily dogfooding the IoC project (and others) lately and I finally took the time today to back-port the fixes and updates to the public code. This is being used for a solution that runs on both the desktop and the compact framework, so it's been heavily tested under both of those environments. The new release (1.0.11235) is now available on Codeplex.

Tuesday, August 23, 2011 1:23:26 PM (Central Daylight Time, UTC-05:00)  #     | 

Like most people, the more projects I work on the more I find myself reusing common bits and pieces of code. For the past year or so I've been collecting these pieces into a library I called OpenNETCF.Extensions.  The name was becasue they originally started as a set of extension methods that helped me to compile one code base for Windows Phone, the Compact Framework and the full framework, but it eventually started expanding in scope.  I added a fairly robust set of method for validation, a set of classes for helpiing make REST clients, a class for a circular buffer (FIFO) and generally anything I found myself using on multiple projects.

Since many of those projects are already open-source, it started becoming a pain maintaining a single, controlled source for these helpers.  So in an attempt to centralize it, I've created yet one more open source project.  My plan now is to have all of the consuming projects only use binary releases from this project.

So, with that said, go ahead and check out the new MIT-licensed OpenNETCF Extensions project over on Codeplex.

Tuesday, August 23, 2011 12:52:23 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, August 19, 2011

I'm going through the Smart Device Framework's WZC code doing testing and hardening (yes, I realize it's long overdue) and I realize that it's not all that clear how to add a preferred network to a wireless adapter.  I've created the beginnings of a new Service class for the OpenNETCF IoC framework (though it's not required that you use IoC to use the service) that will help applications manage things.  I'll come back and update this code as I expand the service due to dogfooding it, but here's the start:

 

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace OpenNETCF.Net.NetworkInformation
{
    public delegate void ScanCompleteDelegate(AccessPoint[] newNetworks, AccessPoint[] lostNetworks, AccessPoint[] stillAvailableNetworks);

    public class WiFiService
    {
        private List m_knownAPs = new List();
        private object m_syncRoot = new object();
        private AutoResetEvent m_stopScanEvent = new AutoResetEvent(false);
        private WirelessZeroConfigNetworkInterface m_wzc;

        public event ScanCompleteDelegate ScanComplete;

        public int ScanPeriod { get; set; }
        public bool Scanning { get; private set; }

        public WiFiService(WirelessZeroConfigNetworkInterface netInterface)
        {
            m_wzc = netInterface;

            // default to a 2 second network scan period
            ScanPeriod = 2000;
        }

        ~WiFiService()
        {
            StopScanning();
            m_knownAPs.Clear();
        }

        public void StartScanning()
        {
            if (Scanning) return;

            new Thread(ScanThreadProc) { IsBackground = true }
            .Start();
        }

        public void StopScanning()
        {
            if (!Scanning) return;

            m_stopScanEvent.Set();
            m_knownAPs.Clear();
        }

        public bool ConnectToOpenNetwork(string ssid)
        {
            return ConnectToNetwork(ssid, null, false, AuthenticationMode.Open, WEPStatus.WEPDisabled);
        }

        public bool ConnectToOpenNetwork(AccessPoint accessPoint)
        {
            return m_wzc.AddPreferredNetwork(accessPoint);
        }

        public bool ConnectToWEPNetwork(string ssid, string wepKey)
        {
            return ConnectToNetwork(ssid, wepKey, false, AuthenticationMode.Open, WEPStatus.WEPEnabled);
        }

        public bool ConnectToWEPNetwork(AccessPoint accessPoint, string wepKey)
        {
            return ConnectToWEPNetwork(accessPoint.Name, wepKey);
        }

        /// 
        /// This connects to a WPA network using TKIP encryption.
        /// 
        /// 
        /// 
        /// 
        public bool ConnectToWPANetwork(string ssid, string passphrase)
        {
            return ConnectToNetwork(ssid, passphrase, false, AuthenticationMode.WPAPSK, WEPStatus.TKIPEnabled);
        }

        /// 
        /// This method will only connect to a WPA2 network using AES.
        /// If you need fallback to WPA (using TKIP), use the overload that takes in an AccessPoint
        /// 
        /// 
        /// 
        /// 
        public bool ConnectToWPA2Network(string ssid, string passphrase)
        {
            return ConnectToNetwork(ssid, passphrase, false, AuthenticationMode.WPA2PSK, WEPStatus.AESEnabled);
        }

        /// 
        /// Connects to a WPA or WPA2 (AES or TKIP)
        /// 
        /// 
        /// 
        /// 
        public bool ConnectToWPANetwork(AccessPoint accessPoint, string passphrase)
        {
            // quick validation
            var valid = accessPoint.AuthenticationMode == AuthenticationMode.WPA
                || accessPoint.AuthenticationMode == AuthenticationMode.WPAPSK
                || accessPoint.AuthenticationMode == AuthenticationMode.WPA2
                || accessPoint.AuthenticationMode == AuthenticationMode.WPA2PSK;

            if (!valid)
            {
                throw new InvalidOperationException("The provided AP is not set up for WPA");
            }

            return ConnectToNetwork(accessPoint.Name, passphrase, false, accessPoint.AuthenticationMode, accessPoint.Privacy);
        }

        private void ScanThreadProc()
        {
            lock (m_syncRoot)
            {
                Scanning = true;

                do
                {
                    var et = Environment.TickCount;

                    var current = m_wzc.NearbyAccessPoints;

                    var added = current.Except(m_knownAPs);
                    var lost = m_knownAPs.Except(current);
                    var updated = m_knownAPs.Intersect(current);

                    m_knownAPs = current.ToList();

                    var handler = ScanComplete;

                    et = Environment.TickCount - et;
                    Debug.WriteLine(string.Format("Network scan took {0}ms", et));

                    if (handler != null)
                    {
                        handler(added.ToArray(), lost.ToArray(), updated.ToArray());
                    }
                } while (!m_stopScanEvent.WaitOne(ScanPeriod, false));

                Scanning = false;
            }
        }

        private bool ConnectToNetwork(string ssid, string passphrase, bool adhoc, AuthenticationMode mode, WEPStatus encryption)
        {
            EAPParameters eap = null;

            switch (mode)
            {
                case AuthenticationMode.WPA:
                case AuthenticationMode.WPAPSK:
                case AuthenticationMode.WPA2:
                case AuthenticationMode.WPA2PSK:
                    eap = new EAPParameters()
                    {
                        Enable8021x = true,
                        EapType = EAPType.Default,
                        EapFlags = EAPFlags.Enabled,
                    };
                    break;
            }

            // stop scanning while connecting
            var wasScanning = Scanning;
            StopScanning();

            try
            {
                lock (m_syncRoot)
                {
                    return m_wzc.AddPreferredNetwork(ssid,
                        !adhoc,
                        passphrase,
                        1,
                        mode,
                        encryption,
                        eap);
                }
            }
            finally
            {
                if (wasScanning) StartScanning();
            }
        }
    }
}
Friday, August 19, 2011 11:08:04 AM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, October 28, 2010

I've published a new release of the OpenNETCF.ORM library.  Some notable additions are:

  • The ORM can now detect added Entity fields and automatically add the underlying columns to the store
  • A new Select override can now filter result sets by multiple fields
  • I've added a skeleton for a SQLite/Windows Phone 7 project with some implementation

If you have a desire to help me get the WinPhone implementation completed, I really could use the extra help.  I'm pretty busy, and without external help on this I don't see it getting implemented any time soon (unless we get hired to do a WinPhone project of course).

If you're not up on what the OpenNETCF ORM library is, in short it's an open-source ORM that actually works on the CF (NHibernate and Entity Framework do not). 

Thursday, October 28, 2010 12:44:56 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, October 13, 2010

Even at version 3.5, the image manipulation capabilities of the Compact Framework are seriously crappy lacking.  I've had all sorts of challenges over the years getting apps to do exactly what I want.  Fortuantely the CF also allows you to do just about anything you can imagine as long as you're willing to roll up your sleeves and dive into the ugliness of interop.

Today I decided to to to create a simple app that would use large images.  Let's say you have a modern camera - you know, something made after 1990 that actually generates pictures of a resolution a bit above 240x480.  The challenge with these images is that in order to display them, they have to be uncompressed to a Bitmap, so if you have a picture that is 2048x1536 at a depth of 24 bits per pixel, you're talking almost 10MB or RAM just to hold that image.  It doesn't take long before you're going to have memory pressure issues (in fact you'll probably have them just trying to load it).

My goal was to display the entire image on my device screen and then allow the user to zoom in on a small area of the image (the zoom is really just a "show this section at the images native resolution" operation).  This simply cannot be done with the System.Drawing namespace.  If you do manage to load the image, you can't get it to paint both the stretched image as the zoom becasue you simply don't have the RAM for it.

This is where the SDF's Imaging namespace comes in.  The Imaging namespace wraps the COM objects in the Imaging library.  It took a little work, but I generated a quick helper class to generate both thumbnails and clips:

 

public static class ImageHelper
{
    private static ImagingFactory m_factory;

    private static ImagingFactory GetFactory()
    {
        if (m_factory == null)
        {
            m_factory = new ImagingFactory();
        }

        return m_factory;
    }

    public static Bitmap CreateClip(StreamOnFile sof, int x, int y, int width, int height)
    {
        IBitmapImage original = null;
        IImage image = null;
        ImageInfo info;

        GetFactory().CreateImageFromStream(sof, out image);
        try
        {
            image.GetImageInfo(out info);

            GetFactory().CreateBitmapFromImage(image, info.Width, info.Height,
                info.PixelFormat, InterpolationHint.InterpolationHintDefault, out original);

            try
            {
                var ops = (IBasicBitmapOps)original;
                IBitmapImage clip = null;

                try
                {
                    var rect = new RECT(x, y, x + width, y + height);
                    ops.Clone(rect, out clip, true);

                    return ImageUtils.IBitmapImageToBitmap(clip);
                }
                finally
                {
                    Marshal.ReleaseComObject(clip);
                }
            }
            finally
            {
                Marshal.ReleaseComObject(original);
            }
        }
        finally
        {
            Marshal.ReleaseComObject(image);
        }
    }

    public static Bitmap CreateThumbnail(StreamOnFile sof, int width, int height)
    {
        IBitmapImage thumbnail;            
        IImage image;
        ImageInfo info;

        GetFactory().CreateImageFromStream(sof, out image);
        try
        {
            image.GetImageInfo(out info);

            GetFactory().CreateBitmapFromImage(image, (uint)width, (uint)height, 
                info.PixelFormat, InterpolationHint.InterpolationHintDefault, out thumbnail);
            try
            {
                return ImageUtils.IBitmapImageToBitmap(thumbnail);
            }
            finally
            {
                Marshal.ReleaseComObject(thumbnail);
            }
        }
        finally
        {
            Marshal.ReleaseComObject(image);
        }
    }

    public static Size GetRawImageSize(StreamOnFile sof)
    {
        IImage image;
        ImageInfo info;

        GetFactory().CreateImageFromStream(sof, out image);
        try
        {
            image.GetImageInfo(out info);

            return new Size((int)info.Width, (int)info.Height);
        }
        finally
        {
            Marshal.ReleaseComObject(image);
        }
    }
}

With that, creating the actual application became nearly trivial:

public partial class Form1 : Form
{
    StreamOnFile m_stream;
    Size m_size;

    public Form1()
    {
        InitializeComponent();
        thumbnail.MouseDown += new MouseEventHandler(thumbnail_MouseDown);
    }
    
    private void load_Click(object sender, EventArgs e)
    {
        var stream = File.Open("\\Program Files\\ThumbnailExample\\bigimage.jpg", FileMode.Open);
        m_stream = new StreamOnFile(stream);

        m_size = ImageHelper.GetRawImageSize(m_stream);
        thumbnail.Image = ImageHelper.CreateThumbnail(m_stream, thumbnail.Width, thumbnail.Height);

        size.Text = string.Format("{0}x{1}", m_size.Width, m_size.Height);
        load.Enabled = false;
    }

    void thumbnail_MouseDown(object sender, MouseEventArgs e)
    {
        // scale
        int x = (e.X * (m_size.Width / thumbnail.Width)) - (clip.Width / 2);
        int y = (e.Y * (m_size.Height / thumbnail.Height)) - (clip.Height/ 2);

        if (clip.Image != null) clip.Image.Dispose();

        clip.Image = ImageHelper.CreateClip(m_stream, x, y, clip.Width, clip.Height);
    }
}

And the output looks something like this:

 

Wednesday, October 13, 2010 3:22:29 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, September 28, 2010

Getting file version info in the Compact Framework is pretty simple - provided the file you want info on is a managed assembly.  But what if you want to get the version info for a native file?  Well it's not quite so nice.  As usual, you have to drop down and P/Invoke several Win32 APIs.  In this case we need to call GetFileVersionInfoSize, GetFileVersionInfo, and VerQueryValue.  We then have to parse the results from these files which, if you're a beginner or not familar or comfortable with raw memory access (i.e. pointer fun), can be really challenging.

I put together a quick example class that extracts not only the file version, but the entire string table, so you can get things like the Company Name and Copyright info as well.  Here's the code:

public static class NativeFile
{
  public struct NativeFileInfo
  {
    public Version Version;
    public NameValueCollection StringTable; 
  }
  public unsafe static NativeFileInfo GetFileInfo(string path)
  {
    if (!File.Exists(path))
    {
      throw new FileNotFoundException();
    }

    IntPtr handle;

    var size = GetFileVersionInfoSize(path, out handle);
    var buffer = Marshal.AllocHGlobal(size);
    try
    {
      if (!GetFileVersionInfo(path, handle, size, buffer))
      {
        throw new Win32Exception(Marshal.GetLastWin32Error());
      }

      IntPtr pVersion;
      int versionLength;
      VerQueryValue(buffer, "\\", out pVersion, out versionLength);

      var versionInfo = (VS_FIXEDFILEINFO)Marshal.PtrToStructure(pVersion, typeof(VS_FIXEDFILEINFO));

      var version = new Version((int)versionInfo.dwFileVersionMS >> 16,
                                (int)versionInfo.dwFileVersionMS & 0xFFFF,
                                (int)versionInfo.dwFileVersionLS >> 16,
                                (int)versionInfo.dwFileVersionLS & 0xFFFF);

      // move to the string table and parse
      var pStringTable = ((byte*)pVersion.ToPointer()) + versionLength;
      var strings = ParseStringTable(pStringTable, size - versionLength);

      return new NativeFileInfo
      {
        Version = version,
        StringTable = strings
      };
    }
    finally
    {
      Marshal.FreeHGlobal(buffer);
    }
  }

  private unsafe static NameValueCollection ParseStringTable(byte *pStringTable, int length)
  {
    NameValueCollection nvc = new NameValueCollection();

    byte *p = pStringTable;
    short stringFileInfoLength = (short)*p;
    byte* end = pStringTable + length;

    p += (2 + 2 + 2); // length + valuelength + type
    // verify key
    var key = Marshal.PtrToStringUni(new IntPtr(p), 14);
    if (key != "StringFileInfo") throw new ArgumentException();

    // move past the key to the first string table
    p += 30;
    short stringTableLength = (short)*p;
    p += (2 + 2 + 2); // length + valuelength + type
    // get locale info
    key = Marshal.PtrToStringUni(new IntPtr(p), 8);

    // move to the first string
    p += 18;

    while (p < end)
    {
      short stringLength = (short)*p;
      p += 2;
      short valueChars = (short)*p;
      p += 2;
      short type = (short)*p;
      p += 2;

      if (stringLength == 0) break;

      if ((valueChars == 0) || (type != 1))
      {
        p += stringLength;
        continue;
      }

      var keyLength = stringLength - (valueChars * 2) - 6;
      key = Marshal.PtrToStringUni(new IntPtr(p), keyLength / 2).TrimEnd('\0');
      p += keyLength;
      var value = Marshal.PtrToStringUni(new IntPtr(p), valueChars).TrimEnd('\0');
      p += valueChars * 2;

      if ((int)p % 4 != 0) p += 2;

      nvc.Add(key, value);
    }
    return nvc;
  }

  private const string COREDLL = "coredll.dll";

  [DllImport(COREDLL, SetLastError = true)]
  private static extern int GetFileVersionInfoSize(string lptstrFilename, out IntPtr lpdwHandle);

  [DllImport(COREDLL, SetLastError = true)]
  private static extern bool GetFileVersionInfo(string lptstrFilename, IntPtr dwHandle, int dwLen, IntPtr lpData);

  [DllImport(COREDLL, SetLastError = true)]
  private static extern bool VerQueryValue(IntPtr pBlock, string lpSubBlock, out IntPtr lplpBuffer, out int puLen);

  [StructLayout(LayoutKind.Sequential)]
  private struct VS_FIXEDFILEINFO
  {
    public DWORD dwSignature;
    public DWORD dwStrucVersion;
    public DWORD dwFileVersionMS;
    public DWORD dwFileVersionLS;
    public DWORD dwProductVersionMS;
    public DWORD dwProductVersionLS;
    public DWORD dwFileFlagsMask;
    public DWORD dwFileFlags;
    public FileOS dwFileOS;
    public FileType dwFileType;
    public DWORD dwFileSubtype;
    public DWORD dwFileDateMS;
    public DWORD dwFileDateLS;
  };

  public enum FileOS : uint
  {
    Unknown = 0x00000000,
    DOS = 0x00010000,
    OS2_16 = 0x00020000,
    OS2_32 = 0x00030000,
    NT = 0x00040000,
    WindowsCE = 0x00050000,
  }

  public enum FileType : uint
  {
    Unknown = 0x00,
    Application = 0x01,
    DLL = 0x02,
    Driver = 0x03,    
    Font = 0x04,
    VXD = 0x05,
    StaticLib = 0x07
  }
}

One item that might not be intuitive is that I'm using an alias for the DWORD type, so up at the top of the code page add this:

using DWORD = System.UInt32;

I then created a quick sample app that pulled the info from the corecon file on my device:

class Program
{
  static void Main(string[] args)
  {
    string target = "\\FlashFX Disk\\ARMv4i\\conmanclient2.exe";
    var version = NativeFile.GetFileInfo(target);

    Console.WriteLine(string.Format("File: {0}", Path.GetFileName(target)));
    Console.WriteLine(string.Format("Version: {0}", version.Version.ToString(4)));
    foreach (var key in version.StringTable.AllKeys)
    {    
      Console.WriteLine(string.Format("{0}: {1}", key, version.StringTable[key]));
    }

    Console.ReadLine();
  }

}

And this is the output:

 


	
Tuesday, September 28, 2010 11:07:30 AM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, September 27, 2010

Are you missing Compact Framework (not Windows Phone, but everything else) support in Studio 2010?  Let Microsoft know and vote here.

Monday, September 27, 2010 11:33:49 AM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, September 20, 2010

I've been developing for Windows CE for a while now, and generally speaking I've seen just about every class of business problem that people might run into.  Or so I thought.

I had a request from a client who wanted to change the default mouse cursor on their device for their solution.  The challenge was that their solution consists of not just one application, but two, and one is a managed application.

Initial research on the web said that this would be fairly easy.  Just put the cursor file out in the file system somewhere, then have each app load it up at runtime.  If only reality were that simple. 

It turns out that Windows CE is substantially limited in its ability to handle cursors.  The big problem is that LoadCursorFromFile, which is exactly what I needed, flat out doesn't exist in Windows CE.  The managed Cursor class also doesn't have a constructor that takes in a filename (likely because of the lack of that API).  I message around a bit trying to load a Bitmap and use the HBITMAP in some cursor calls, but every step led me to a dead-end.  So after an hour or two of doing nothing but exploring and ruling out options, I decided that maybe I'd accept a limitation that the cursor would have to be embedded as a resource in a native DLL.

Of course this still wasn't super straightforward or simple either. LoadImage can only load an image from a compiled resource file by name.  Of course EnumResourceNames, which you might use to get a resource name, doesn't exist either.

My first goal was to just get the cursor changed for the Form.  I assumed that the cursor would likely not be correct for child controls like TextBoxes, but really, baby steps are fine.  I used LoadLibraryEx to load up the native DLL, followed by LoadCursor to load the cursor resource by ID, then finally a call to SetCursor.

My initial test were returning valid (i.e. non-zero) return values but the cursor would change only briefly.  As soon as I moved the mouse, the cursor would revert to the default.  A little more research and I came across this gem in the MSDN remarks for SetCursor:

"If your application must set the cursor while it is in a window, make sure the class cursor for the specified window's class is set to NULL. If the class cursor is not NULL, the system restores the class cursor each time the mouse is moved."

That sounded a whole lot like the behavior I was seeing.  A little more searching and I came to the conclusion that I needed to call SetClassLong with GCL_HCURSOR.  This required that I give a pointer to the loaded cursor, so I have to move the results of LoadCursor to a broader scope, but once I'd done that, bingo!  The cursor was my custom cursor when on the Form. (I wanted to put a screen shot in this post here, but screen captures on the device omit the mouse cursor, so it's not terribly interesting.)

So now the goal was to get it to not change when I moved over another Control.  Again it was time to do more research.  It turns out that it could be done for each control class (so all TextBoxes, all Forms, etc) but that would mean I'd have to iterate through all of these types and set it.  And who knows what a custom or user control might turn up.  That just seemed risky and kludgy to me.  What are my other options?

It seems that if you handle the WM_SETCURSOR message for a control, you can override the default behavior to set the default cursor.  So all I had to do was subclass my Form.  Of course that's not 100% straightforward with the Compact Framework.  You can't just override WndProc like you can on the desktop, but still it wasn't groundbreaking territory and I'd done it before.  I ended up creating a simple Subclasser class that you could attach to a Form, then in it load up your cursor (using the code I'd done before) and then just call SetCursor with my desired cursor instead of the default.

The end result worked perfectly.  The source code for the work can be downloaded here: CursorTest.zip (9.15 KB) (the native source that holds the actual cursor is here: Cursors.zip (12.56 KB))

Some other thoughts I have on this that I leave to the ambitious:

  • I think you could probably use a similar technique to the Form subclass to do an application-wide cursor replacement using an OpenNETCF.Windows.Forms.IMessageFilter implementation, but I've not tested that.
  • This is going to kill your wait cursor, so if you want/need one, you're going to have to plumb in support for that
  • If you want to have multiple custom cursors (if you want to have a custom Form and a custom TextBox for example), then you're probably going to have to add support for that if you use the subclassing technique.
  • I've noticed that when you click a Button and it redraws, it appears to draw over the cursor until you move the mouse again, so this needs to be looked into.
Monday, September 20, 2010 3:17:05 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, August 17, 2010

I've been using the OpenNETCF.ORM library on a shipping project for a while now.  As expected, as I add features to the product, I've found problems and limitations with the ORM that I've addressed.  This morning I merged that branch back with the trunk available on Codeplex, so there's a whole new set of code available.  New features include:

  • Better handling of reference fields
  • Cascading inserts
  • Cascading deletes
  • Expanded capabilities for filtering on deletes
  • Added support for more data types, including the "object" type
  • Support for ROWGUID column

What it really needs now is a definitive sample application and documentation.  If you'd like to volunteer to work on either, I'd really appreciate it. 

Tuesday, August 17, 2010 8:29:37 AM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, July 28, 2010

Since I use the OpenNETCF.IoC framework in just about every project I do any more, you can imagine I've created a pretty good collection of Modules and Services for common business problems I run into.  I've decided that I'm going to start putting some of these out in the public domain along with the framework and my first release is the OpenNETCF.Location module.  It's basically a module that prvides a GPS location service (GpsService to be exact). 

The default implementation is wrapper around the GPS intermediate driver, but it's not using the CF classes that Microsoft ships with the WinMo SDKs.  I looked at Microsoft's implementation and it felt really ugly to me, so I rewrote it the way it should have been done in the first place.  I don't yet have a simple sample application extracted for it (I have apps that use it, but they're too complex for a sample), but I'll add one as time permits.

The code is part of the latest change set (49823) - it's not yet in the release download - so if you want it, get it off of the Source Code page.

Wednesday, July 28, 2010 11:45:25 AM (Central Daylight Time, UTC-05:00)  #     | 

In my continuing effort to get code that I have lying around out to where it's publicly available and easy to find, I've pushed my old FTP library up to Codeplex.

Wednesday, July 28, 2010 10:45:16 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, July 23, 2010

I've been working on a new control this week that depends a whole lot on transparency and the alpha channel.  The Compact Framework's Bitmap class is actually really, really bad and it's made for all sorts of swearing. 

The design of the control requires me to regularly create a "transparent" background.  We know that you can't create a transparent bitmap directly (which is the fundamental thing that is killing me) so I end up using a TransparentClearBitmap method that first appeared in Project Resistance that does a LockBits and walks the image setting transparency.  This is slow (600ms for my bitmap on the emulator).

I needed to draw on top of this Bitmap to assemble my control layout. The issue is that every time I repainted the control due to a change, I need a new transparent Bitmap and had to pay the 600ms piper.  Needless to say this gave for a really bad user experience.  Well how about just caching the transparent bitmap and returning a copy of it when necessary?  That should be simple, right?

I tried to use the Bitmap constructor to make a copy:

var bmp = new Bitmap(m_transparentBitmap);

Of course it failed. The new Bitmap lost all transparency data.

Well maybe the Clone method would do what I want, after all that's what I needed - an exact clone:

var bmp = m_transparentBitmap.Clone;

Again, all transparency data was lost. Joy.

So it was off to the drawing board to re-implement what should have already been working.  Here's the result - a TransparentBitmap that you can clone and actually keep the transparency info:

public class TransparentBitmap
{
    private Bitmap m_bmp;

    public int Width { get; private set; }
    public int Height { get; private set; }

    public TransparentBitmap(int width, int height)
    {
        Width = width;
        Height = height;
        m_bmp = new Bitmap(width, height, (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        GraphicTools.TransparentClearBitmap(m_bmp);
    }

    private TransparentBitmap(Bitmap image)
    {
        m_bmp = image;
        Width = image.Width;
        Height = image.Height;
    }

    public static implicit operator Bitmap(TransparentBitmap t)
    {
        return t.m_bmp;
    }

    public TransparentBitmap Clone()
    {
        var clone = new Bitmap(Width, Height, (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        var dest = clone.LockBits(
                new Rectangle(0, 0, Width, Height),
                ImageLockMode.WriteOnly,
                (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

        try
        {
            var src = m_bmp.LockBits(
                    new Rectangle(0, 0, Width, Height),
                    ImageLockMode.ReadOnly,
                    (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

            try
            {
                int bytes = src.Width * src.Height * 4;
                memcpy(dest.Scan0, src.Scan0, bytes);
            }
            finally
            {
                m_bmp.UnlockBits(src);
            }
        }
        finally
        {
            clone.UnlockBits(dest);
        }

        return new TransparentBitmap(clone);
    }

    [DllImport("coredll.dll", SetLastError = true)]
    private static extern IntPtr memcpy(IntPtr to, IntPtr from, int count);
}

The Clone takes only about 4ms to run instead of 600ms to create new, so it certainly improved things.

Friday, July 23, 2010 4:02:06 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, July 21, 2010

I'm working on a new control and I ran into the need to know if a pixel in an image is transparent or not (essentially I want to ignore clicks on the control if the underlying color is transparent).  My first reaction was that I'd simply call GetPixel on the underlying Bitmap and look at the Color's A (alpha) value.  Unfortunately, the Compact Framework's implementation always appears to return 0xff (fully opaque) for teh A channel.

Next I figured I'd call LockBits and look at the pixel data manually.  Once again the CF tried to thwart me because the supported PixelFormat enumeration values in the Compact Framework don't include anything with Alpha support.

Instead I decided to try to "fool" the framework by creeating my own PixelFormat enumeration that contained all of the actual possible values, not just the three exposed in the CF:

enum PixelFormat
{
    Indexed = 0x00010000, // Indexes into a palette
    GDI = 0x00020000, // Is a GDI-supported format
    Alpha = 0x00040000, // Has an alpha component
    PAlpha = 0x00080000, // Pre-multiplied alpha
    Extended = 0x00100000, // Extended color 16 bits/channel
    Canonical = 0x00200000,

    Undefined = 0,
    DontCare = 0,

    F1bppIndexed = (1 | (1 << 8) | Indexed | GDI),
    F4bppIndexed = (2 | (4 << 8) | Indexed | GDI),
    F8bppIndexed = (3 | (8 << 8) | Indexed | GDI),
    F16bppRGB555 = (5 | (16 << 8) | GDI),
    F16bppRGB565 = (6 | (16 << 8) | GDI),
    F16bppARGB1555 = (7 | (16 << 8) | Alpha | GDI),
    F24bppRGB = (8 | (24 << 8) | GDI),
    F32bppRGB = (9 | (32 << 8) | GDI),
    F32bppARGB = (10 | (32 << 8) | Alpha | GDI | Canonical),
    F32bppPARGB = (11 | (32 << 8) | Alpha | PAlpha | GDI),
    F48bppRGB = (12 | (48 << 8) | Extended),
    F64bppARGB = (13 | (64 << 8) | Alpha | Canonical | Extended),
    F64bppPARGB = (14 | (64 << 8) | Alpha | PAlpha | Extended),
    Max = 15,
}

Since an enum is really just a number, you can directly cast this to a System.Drawing.Imaging.PixelFormat. Nicely (and fortunately), the CF implementation of LockBits doesn't check to ensure that the value you pass in is one of the defined PixelFormat values and it readly accepts this cast value.  Even more interesting is that it returns a set of data with the proper alpha channel data. 

Gettting the Alpha data, then is as easy as this (I don't return a Color because there is no easy way to create a Color class that contains Alpha data in the CF either):

private byte GetPixelAlpha(Bitmap image, Point point)
{
    var d = image.LockBits(new Rectangle(0, 0, this.Width, this.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly,
            (System.Drawing.Imaging.PixelFormat)PixelFormat.F32bppARGB);

    try
    {
        // the CF's GetPixel method will always return 0xff (full opaque) for the alpha channel
        // so we have to resort to unsafe shenanigans
        unsafe
        {
            int offset = (d.Width * point.Y * 4) + (point.X * 4);
            byte* p = (byte*)d.Scan0;
            p += offset;

            return *(p + 3);
        }
    }
    finally
    {
        image.UnlockBits(d);
    }
}

Wednesday, July 21, 2010 3:50:57 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, May 18, 2010

Let me lead off by saying I'm a bit of a luddite when it comes to phones. I like my phone to be able to make a call and occasionally send a text message. If I need to use a browser, I have a 30-inch Dell monitor and a PC that I can actually read web pages on. If I need to find a location, I have a nice Nuvi that doesn't require men to fiddle with a phone and that has a better interface that any other phone I've used. If I need to listen to music I have a Zune that lets me do that.

As far as phones go my favorite, other than that old StarTac that I still pine for, is my HTC Snap (also known as an HTC Ozone, Dash 3G and probably a few other names). Ironically it's also the target of my wrath over the last few days. As a user experience as far as a phone goes, it has everything I like, but if you need to actually create an application that does what you want on the thing, I think you're going to need divine intervention. And this, at its core, is why I think Windows Mobile, at least up through 6.5 just plain sucks.

My goal was simple - or so I thought. Create a simple application that collects GPS data at all times (yes, I know about battery life, blah, blah - let's assume that it's not an issue for this app). I know that a Smartphone never actually puts the processor fully to sleep and that even when the backlight/screen is off, I can still run code so this should be simple, right? Hardly.

Strike 1

The first thing I found, which was not a surprise, is that when the phone enters the "screen off" power mode, it shuts off the GPS receiver - or that's what I assume anyway. The GPSID driver stops giving me data anyway.

I know from cruising around the device's registry that the driver prefix is "GPD0:" and I know that WinMo is supposed to allow you to adjust power schemes through both API calls and some registry settings. "Supposed to" being the key here. I spent well over an hour going through and modifying the registry keys adding just about every combination I could think of along with soft resetting the device all with zero effect.

This is the first strike against this platform. Microsoft has documented that this is how the device is supposed to work, yet in a real-world scenario, it doesn't.

Strike 2

I know a bit about how Windows CE works, and my assumption is that these registry settings simply tell the Power Manager to set some driver device states under certain conditions. There should be no reason I can't do that manually, since I'm dealing with a pretty finite set of drivers (one) and states (two).

In order to manually alter the power state of a device, I need to know when the system itself changes state. For example, I need to know when the device goes into Unattended mode so I can then manually call one of the power management functions. To get notifications, we P/Invoke RequestPowerNotifications and pass it in a queue handle where it will send those notifications. Another hour of development later and I came to the conclusion that the device simply isn't sending out notifications for power state changes. I tested this in both C# and C to just be certain. Strike two.

Maybe I could just do something simple and just tell the Power Manager to never shut off the GPS. SetPowerRequirement should do that, but more testing proved that this, too, had no effect on this platform. After several hours of work and lots of frustrating tests that failed I was beginning to question the power manager altogether.

Strike 3

If the device wasn't going to tell me when it changes state, then I figured I'd just handle all of the state changes myself. I'd have the application periodically call SystemIdleTimerReset, implement my own application idle filter and dim the backlight myself. We're getting into some serious hack territory here, but some days you have to do what you have to do to solve the issue.

I implemented the timeout filter and used a call to SetDevicePower to shut off the backlight. The idea here is that I'd just never let the device go into the BacklightOff or Unattended mode and just turn off the backlight myself. I ran the test and ,surprise, my code had zero effect.   By zero effect I mean that the backlight shut off and the GPS turned off.

 I spent some time debugging to try to determine why I was able to shut off the backlight but not keep the GPS on and I finally realized that I was actually not turning off the backlight - the device still was. For the first time ever I was seeing a call to SystemIdleTimerReset succeed (i.e. return a success) but not  actually reset the timer. Strike three, and this was a huge one.

Conclusion

I continued to muck about with other APIs like PowerPolicyNotify to try to keep the backlight on and even some proprietary HTC calls I found online, all to no avail. I went back to basics and tried even the simplest of code in C and re-verified all that I had seen.The device appeared to completely ignore any call that had to do with the Power Manager while always giving me a successful return value.

All I can conclude from this is that HTC, in their infinite wisdom, decided to implement their own power manager to handle turning on/off all of these devices. and to make the WinMo platform itself happy, they just stubbed out all of the Power Manager calls to return success.

In the end, I told the customer that the phone they selected will never be able to do what they want and it looks like they're going to opt for another phone running a completely different OS.

This is a classic case of why I hate developing software the Windows Mobile platform, and one of the big reasons why the platform has been pretty much an abject failure. How can a software vendor even hope to develop an application that will work on multiple devices when the devices don't even follow Microsoft's published rules? The test matrix would be astronomically large and the costs, both in terms of the hardware you'd have to keep on hand and the time required to run the tests is simply prohibitive.

So is this HTC's fault? To a degree, sure. They should have followed the API's documented by Microsoft, but I still only place about 10% of the blame on them. Developers will, after all, always try to do things "better", and by better I mean that anything not designed in-house is obviously inferior.

But the real problem lies in Redmond. Every Windows Mobile device that ships gets a Windows Mobile logo. To get that logo they have to run the device through a set of Logo Certification tests (also called the LTK). The fact that a device can pass those tests with these obvious and fundamental variances shows that either the tests themselves have really poor coverage or the OEMs are getting waivers for these test failures.

Which it is doesn't matter because the end result is that Logo Testing is completely meaningless. The idea behind Logo Testing should be that when an ISV gets a device, they can depend on it to behave in a specific, predictable way. This device certainly doesn't. And this was just one device and just a small handful of APIs that I was attempting to use. Extrapolate that out to all of the device models that have been shipped and all of the APIs that any given application might call and you begin to see why this is so difficult (and very likely one of the reasons Windows Phone 7 is a complete redesign all the way back at to base Windows CE OS).

Personally, I don't do a whole lot of Windows Mobile development. I tend to focus on embedded Windows CE solutions where the hardware, OS and API set are fixed, finite, manageable and testable. When I see something wrong, we get the OS fixed - we don't path over the top of it (at least whenever we can). It's these little forays back into the Windows Mobile platform that reinforce and remind me of my utter distaste for it.

Hopefully Windows Phone 7 will have valid platform testing and a meaningful certification program but the reality is that I, and likely many, many other developers have been jaded by bad experience after bad experience with these and it's going to take a whole lot of work to gain our trust back. I'm not saying it's an insurmountable problem, but I certainly don't think Microsoft is going to get many more chances.

Tuesday, May 18, 2010 1:23:03 PM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, May 17, 2010

Microsoft has finally declared the NNTP newsgroups dead.  It's where I've done my "community  service" for the past decade or so, so I'm a bit sorry to see them go.  They have started a set of new online Forums (which are live now) to replace these groups.

Monday, May 17, 2010 5:44:34 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, January 13, 2010

Well I blew the VB cobwebs out of my brain this morning and wrote a very basic example of getting AP info like signal strength using the SDF.  It took me nearly 2 hours and a whole lot of search engine work to remind me of syntax to crank out a simple 70-line application (I actually had to find a machine with VB installed first, as it's no longer in my "default" install of Studio).  Hard to believe I was once fluent enough in the language to have written a book.

At any rate, here's the sample: BasicWiFiSample.rar (532.46 KB)

Wednesday, January 13, 2010 12:26:21 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, November 25, 2009

Long, long ago I wrote an article for MSDN on creating a multi-Form CF application that used a Form Stack.  Since we all tend to grow and learn as developers, we find different ways to do things (and generally we scoff at code we wrote years before as inferior crap). 

Well Peter Nowak is giving a presentation of the OpenNETCF.IoC framework next week and I decided that a sample of using the UI elements of the library (Workspaces, SmartParts, etc) might be handy and so I decided to rewrite the Form Stack following my latest thinking.  Basically the idea is to allow a user to navigate through Forms (actually Views - you are separating your Views from the Model, right?) like you would on a browser.  You can move forward and back as well as "adding" to the end or top of the stack.  We also don't want to be constantly creating new instances of the View classes because we like applications to perform well.

Here's a look at the new application (yes, I know it's "developer ugly" but this is about architecture, not aesthetics):

You can see the stack in the list, and our current position is noted by the asterisk.  "Fwd" will move down to View B, "Back" will move up to Form A, or you can push a new A or B onto the stack at the current location, which will truncate everything currently above (after) the current position.  Again, think of how your browser works.  It's important to know, also, that there are only 3 total View instances created at this point (one of each specific type).

The code for this application is in source control over at the OpenNETCF.IoC Framework Codeplex site.  You'll notice it's called FormStackCS, hinting that there may be a FormStackVB coming.  If you'd like to volunteer to do that port, by all means let me know (meaning don't hold your breath waiting for me to do it).

Wednesday, November 25, 2009 11:21:11 AM (Central Standard Time, UTC-06:00)  #     | 
# Friday, November 20, 2009

If you've ever done mstest unit testing with a Smart Device project, then you're painfully aware of how badly Microsoft dropped the ball on this one.  Debugging a unit test requires making device registry modifications, adding a call to Debugger.Break in your code, then telling Studio to Attach to Remote Process once the breakpoint has been hit.  Seriously, that's their officially published answer to how you debug a Smart Device unit test!

If you know anything about testing, you know that keeping the cycle time for a test to a minimum.  The longer it takes a developer to go from "start testing" to a break point where they can step, then the less productive they're going to be.  Even worse, if the process is painful, slow and convoluted (check, check and check for Microsoft's recommendation), they're likely to just skip writing tests altogether.

Internally we get around this by using our own test runner which uses Reflection to load up and run tests.  I've decided to once again give back to the community and publish this gem as part of Project Resistance (it will get checked in to the IoC Framework as well).

It does not support everything that mstest does, but it's got enough to get you going, and I think it's at least reasonably easy to modify if it doesn't meet your needs.  The currently supported attributes are:

It also might now be obvious how to set it up for your own app.  You need to add a reference to your test assemblies (so VS will deploy them - for some stupid reason you can't tell it to do so via the Configuration Manager) and make sure all projects are set to deploy to the same place.

As usual, if you have feedback or updates, please let me know.  Submitting a patch right on one of the project portals is probably the easiest way (hint, hint).

It's probably worth noting here that the code for this is the CFTestRunner project, and you have to pull it from the source tab on the project site (it's not in the release download yet).

Friday, November 20, 2009 12:36:06 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, August 26, 2009

I've pushed another ode update for the OpenNETCF IoC Framework into Codeplex.  Highlights in this one are the fact that I've added a WorkItems collection to the WorkItem class, meaning there's now the potential for parent/child relationships.

Wednesday, August 26, 2009 8:11:29 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, June 25, 2009

Over the past few months we've been working hard to consolidate the products we at OpenNETCF offer.  What this means is that products that didn't sell well or that had high support loads compared to sales got dropped.  Our Telephony library is one of those that we decided to discontinue.  But that's good news for all!  Instead of just letting it wither and die in the depths of our own source control server, we figure it might as well be thrown out to the community to see if it will flourish.

SO with that, we give you the OpenNETCF.Telephony Library, hosted over at Codeplex as tapi.codeplex.com.  Enjoy.

Thursday, June 25, 2009 6:06:39 PM (Central Daylight Time, UTC-05:00)  #     | 

We're going to be adding a full set of custom-drawn and owner-drawn controls in the next version of the SDF.  These are not "new" controls, but wrappers around the existing native control, but we're adding the custom and owner draw hooks that the OS already provides (and that, honestly, the CF team should have given us by version 3.5). 

In testing them out, I wanted to dogfood the custom-drawn ListView in an application, but I needed to know when a user clicked on an item in the ListView.  Simple.  Or so I thought.  It turns out that the style bits that get set to make a ListView really usable means that the ListView's *parent* gets it's click actions, and to turn those into Click events in the managed control is a *lot* of work, and would likely have some performance penalty.

So that got me to wondering how the existing CF ListView deals with it.  Well after a very quick test it seems that the CF team made the same decision - they didn't support the Click event either

Well my application requires that I know the difference between when the selected index changes (that's about the only useful event you do get) due a click and and when it changes dues to a keyboard action like an up or down arrow. Being me, I refuse to change the way I want my application will work just becasue of some stupid limitation of a framework.  The OS knows when I click on that damned thing - after all, it changes the selected item - so it *will* tell my application when it happens.

The key here is pretty simple.  We know that the click event does come in, and it comes in as a Windows message.  Our application message pump routes it to the parent of the ListView - so we have two point at which we can try to get it.  Getting it from the parent would entail subclassing the parent Form, and that just does seem like fun, nor is it really extensible if I ever have another app where I want to get ListView item clicks.

So that leaves looking at the application message pump.  Unfortunately the CF team has again not seen fit in any version to provide us the ability to add an IMessageFilter, but this was something we overcame long ago in the SDF.  If you use the Application2.Run method, you can then add IMessageFilters.  So what I did here is created an IMessageFilter that looks for messages whose hWnd matches the ListView I'm interested in, and then looks for the WM_LBUTTONDOWN message:

internal class ClickFilter : IMessageFilter
{
  private Control m_control;

  public event EventHandler Click;
  public event MouseEventHandler MouseDown;

  public ClickFilter(Control control)
  {
    m_control = control;
  }

  private int LoWord(IntPtr param)
  {
    return (ushort)(param.ToInt32() & ushort.MaxValue);
  }

  private int HiWord(IntPtr param)
  {
    return (ushort)(param.ToInt32() >> 16);
  }

  public bool PreFilterMessage(ref Microsoft.WindowsCE.Forms.Message m)
  {
    if (m_control.IsDisposed) return false;

    if ((m.HWnd == m_control.Handle) && (m.Msg == (int)Microsoft.Controls.WM.WM_LMOUSEDOWN))
    {
      MouseEventArgs args = new MouseEventArgs(MouseButtons.Left, 1, LoWord(m.LParam), HiWord(m.LParam), 0);

      ThreadPool.QueueUserWorkItem(ButtonInvoker, args);
    }

    return false;
  }

  void ButtonInvoker(object o)
  {
    // let the system select the clicked listview item
    Thread.Sleep(10);
    Application2.DoEvents();

    if (m_control.IsDisposed) return;

    if (m_control.InvokeRequired)
    {
      m_control.Invoke(new WaitCallback(ButtonInvoker), new object[] { o });
      return;
    }

    // not truly a click, since it's not a down/up pair. Fix this later if we feel like it
    if(Click != null) Click(m_control, null);
    if (MouseDown != null) MouseDown(m_control, o as MouseEventArgs);
  }
}

Take note of the slight kludge in there though with the ThreadPool.  The reason for this is that if you just raise the event immediately on getting the mouse down event, the ListViewItem selection won't have happened yet, so if your handler looks at the SelectedItem, it would get the item that was selected before the click, not the one that the was clicked. 

Sure, maybe that's what your app wants, but in my case I wanted to know which item is actually clicked.  The ListView doesn't support a HitTest method (again, why don't we have this yet?), so knowing the x,y coordinates of the click is still a long way from giving us the ListViewItem.  This was a kludge to easily get me the info I wanted.

So using this filter in my application was as easy as adding this to the Form that contains the ListView:

InitializeComponent();

ClickFilter filter = new ClickFilter(listView);
filter.Click += new EventHandler(filter_Click);
Application2.AddMessageFilter(filter);

No, it shouldn't be this hard.  I wish the CF team would spend more time fixing fundamental stuff like this instead of tilting at the Silverlight windmill, but it is what it is, and as developers we still have to ship solutions.

Thursday, June 25, 2009 10:27:26 AM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, June 24, 2009

It took a long time to get here, but we've finally release what I'm calling the version 1.0 (pervious version were 0.9.x) release of the OpenNETCF.IoC Framework.  In case you've not been tracking this project, it is a public-domain-licensed (you can't get any more free and unencumbered than that) framework that provides both inversion of control and dependency injection for .NET Compact Framework applications (it can be used on the desktop as well).  It's roughly modelled after Microsoft's SCSF and CAB frameworks, but it's scaled down and optimized for running on mobile and embedded devices, plus I "fixed" stuff that I think the SCSF got wrong (like having a static, globally available RootWorkItem and the ability to insert IMessageFilters into the application's message pump).

This framework is in use in a couple of commercial applications already, so it's been pretty heavily tested and vetted.  I still want to add a few more features as well and go back through it looking for performance optimizations, but it certainly has enough features to be used in applications today.

This release also ships with a full-blown, real-world sample application, not just the typical "Northwind" type of application.  The sample is called WiFiSurvey and it can be used to survey WiFi AP coverage of a site and to monitor associated AP changes as well as network addressability of a device.

WiFiSurvey has a Configuration service, a SQL CE 3.5-backed Data Access Layer, an Infrastructure module and a an application shell all of which are fully decoupled from one another and that are all loaded dynamically using an XML definition file.  The shell makes use of both a DeckWorkspace and a TabWorkspace, showing you not just how to use them, but also how to create your own workspaces if need be.

The WiFiSurvey application has a single source base for all target platforms and has been tested on the following platforms:

  • ARM-based CE 6.0 with a 320x240 (landscape) display.
  • Pocket PC 2003 240x320 (portrait)
  • WinMo 5.0 240x320 (portrait and landscape)

The IoC framework has additionally been tested on x86-based CE 5.0 and CE 6.0 devices.

As a side note, the WiFiSurvey sample application is also a good example of using the OpenNETCF Smart Device Framework for getting wireless information.

Wednesday, June 24, 2009 1:54:24 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, June 17, 2009

So it seems that something has changed in CE 6.0 in the way that user inactivity is detected by the OS.  In CE 5.0 and before, if we wanted to keep the backlight on we could periodically call SystemIdleTimerReset and all would be well.  In CE 6.0, this no longer works.  Now we have to set a named event that GWE is waiting on.  Here's what it looks like (this code uses the SDF for the named EventWaitHandle - the CF doesn't provide one).

private EventWaitHandle m_activityEvent;

[DllImport("coredll", SetLastError=true)]
private static extern void SystemIdleTimerReset();

private void ResetBacklightTimer()
{
  if (Environment.OSVersion.Version.Major <= 5)
  {
    SystemIdleTimerReset();
  }
  else
  {
    if (m_activityEvent == null)
    {
      using (var key = Registry.LocalMachine.OpenSubKey("System\\GWE"))
      {
        object value = key.GetValue("ActivityEvent");
        key.Close();
        if (value == null) return;

        string activityEventName = (string)value;
        m_activityEvent = new EventWaitHandle(false, EventResetMode.AutoReset, activityEventName);
      }
    }

    m_activityEvent.Set();
  }
}

Wednesday, June 17, 2009 4:11:25 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, April 01, 2009

I'm in the middle of adding a Passive View Model-View-Presenter(MVP) framework to the OpenNETCF IoC Framework.  I just checked in a working version (it's in the source downloads, not as a release).  If you're interested and want to have a say in how it ends up, go ahead and download it and give me your feedback.  There's a simple usage example in source control.

Wednesday, April 01, 2009 2:10:37 PM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, March 31, 2009

Another nice addition to the latest drop of the SDF is the ability to get the serial number and manufacturer ID of storage volumes that support it (like SD cards). We did this by simply extending the existing OpenNETCF.IO.DriveInfo class to add a couple new properties.  Here's a quick example of how it works:

foreach(var info in DriveInfo.GetDrives())
{
  Debug.WriteLine("Info for " + info.RootDirectory);
  Debug.WriteLine("\tSize: " + info.TotalSize.ToString());
  Debug.WriteLine("\tFree: " + info.AvailableFreeSpace.ToString());
  Debug.WriteLine("\tManufacturer: " + info.ManufacturerID ?? "[Not available]");
  Debug.WriteLine("\tSerial #: " + info.SerialNumber ?? "[Not available]");
  Debug.WriteLine(string.Empty);
}

Tuesday, March 31, 2009 10:03:33 AM (Central Standard Time, UTC-06:00)  #     | 

The latest drop of the SDF adds a nice little feature for playing tones with the device.  It works a lot like the old Beep API on the desktop where you provide a frequency and a duration and it plays the tone.

Here's a quick example of how it works:

Tone[] scale = new Tone[]
{
  // up fast, using MIDI
  new Tone { Duration = 10, MIDINote = 63},
  new Tone { Duration = 10, MIDINote = 65},
  new Tone { Duration = 10, MIDINote = 67},
  new Tone { Duration = 10, MIDINote = 68},
  new Tone { Duration = 10, MIDINote = 70},
  new Tone { Duration = 10, MIDINote = 72},
  new Tone { Duration = 10, MIDINote = 74},
  new Tone { Duration = 10, MIDINote = 75},

  // down slow, using freq (same notes as above)
  new Tone { Duration = 100, Frequency = 622 },
  new Tone { Duration = 100, Frequency = 587 },
  new Tone { Duration = 100, Frequency = 523 },
  new Tone { Duration = 100, Frequency = 466 },
  new Tone { Duration = 100, Frequency = 415 },
  new Tone { Duration = 100, Frequency = 391 },
  new Tone { Duration = 100, Frequency = 349 },
  new Tone { Duration = 100, Frequency = 311 },
};

SoundPlayer.PlayTone(scale);

You can see that this just plays an ascending scale of notes quickly, then the same scale descending, but slower.  Note that the PlayTone method takes in an array of Tones, and a Tone can be initialized with either a Frequency or MIDI note value.

Tuesday, March 31, 2009 9:57:42 AM (Central Standard Time, UTC-06:00)  #     | 
# Friday, March 20, 2009

OpenNETCF used to have a product that provided RAS capabilities.  Well Microsoft deprecated RAS in WindowsMobile - starting with WinMo 5.0 as near as I can figure - in favor of Connection Manager.  That depracation actually broke RAS in some scenarios.  FOr example, if you create a RAS connection and then try to use a managed TcpClient, it will try to create it's own connection through the Connection Manager instead of using the connection you created through RAS.

What this did was skyrocket our support incidents for something that we sold very, very few licenses for.  In the interest of keeping our sanity, yet allowing people using plain of Windows CE to still use RAS, we made the decision to just make it a shared source project.  It's now out on CodePlex.  If you need support for it, we still offer consulting services, but everything is there to get you going.

Friday, March 20, 2009 10:54:05 AM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, March 11, 2009

Articles in this series
Part I: Inversion of Control and the Compact Framework
Part II: The OpenNETCF.IoC Framework: Items and Services
Part III: The OpenNETCF.IoC Framework: Events (this article)
Part IV: The OpenNETCF.IoC Framework: Performance (TBD)

Downloads
Code and Sample available through CodePlex.


In the Part II of this series we looked at how the OpenNETCF.IoC framework provides dependency injection for the lists of Items and Services and if you look at the sample application that ships with the framework you’ll see that the application creates and displays 3 separate Froms and a Service without a single call to the ‘new’ operator anywhere in the solution and, more importantly, without having to pass object references around yourself.

While I find that both fun and useful, the real thing I love about the OpenNETCF.IoC framework (and the SCSF that it’s modeled after) is the implementation of inversion of control through event publication and subscription.

A New Paradigm for Events

In the traditional managed development, an object exposes an event, something like this:

public event EventHandler OnMyEvent;

And when a subscriber wants to get notified of that event, they add a handler delegate like this:

publisherInstance.OnMyEvent += HandleOnMyEvent;

void HandleOnMyEvent(object sender EventArgs args)
{
  // do something useful here
}

That’s all well and good, but in my mind there are two problems with it. First it’s just plain ugly.  I have code in two places, first to attach the event, and second to handle it.  I like to keep related code close together, and this coupling of attaching the handler and the delegate implementation makes that hard (unless you use anonymous delegates). 

The second, and far worse, problem is that it requires that you have the instance of the event publisher to wire this up.  In some cases this is fine, but in others it seems rather pointless.  Let’s go back to one of our early examples of People and Cars and extend it ever so slightly.  We’ll add an event to the Car class :

public delegate void WreckHandler(ICar car);

class Car : ICar
{
  public event WreckHandler OnWreck;
}

And let’s say we have a specialized person – a PoliceOfficer – and he’d like to know any time there is a car wreck.

class PoliceOfficer : Person
{
  public void HandleCarWreck(ICar car) {…}
}

How would we wire this up?  Should we pass every Car instance in town to the officer so he can wire up the event?

class PoliceOfficer : Person
{
  public void HandleCarWreck(ICar car) {…}

  public void WatchCar(ICar car)
  {
    car.OnWreck += HandlerCarWreck;
  }
}

When would we call this?  Every time a Car instance is created?  How would the new Car instance know about the PoliceOfficer?  What if we have multiple Officers?  You can see that this gets real ugly, real fast.  Wouldn’t it be nice if any PoliceOfficer could just listen for the OnWreck event globally and any time any Car instance raised it, he would get notified?  Well that’s what the OpenNETCF.IoC framework’s eventing structure is all about. You publish and subscribe to events based on a unique string name for the event of interest.

So for the event publisher, the Car in this case, we use the same event definition but we add a simple attribute:

class Car : ICar
{
  [EventPublication(“CarWreck”)]
  public event WreckHandler OnWreck;
}

The important piece here is the text string that is sent in to the EventPublication attribute.  It can be any string at all, but it’s that string that event subscribers will use.

Over on the subscriber end it, hooking up the event looks like this:

class PoliceOfficer : Person
{
  [EventSubscription(“CarWreck”, ThreadOption.Caller)]
  public void HandleCarWreck(ICar car) {…}
}

Notice that I’m using the same text string in both.

Now there are a few important notes on using events in the OpenNETCF.IoC framework.  First all of the objects (publishers and subscribers) have to be actually in the framework (in either the Items or Services collection).  In fact with the version of the Framework that ships as I write this, the objects actually have to be created by the framework.  This means that if you create the object manually and then use the Add method to get it into the collection (as opposed to calling AddNew or using an InjectionConstructor or ServiceDependency), then the events won’t get wired up.  I intend to fix this in a future version, but if you pull down the code today, be aware of that limitation.

The second note is in relation to the subscriber.  You’ll see that the EventSubscription attribute takes a ThreadOption as a second parameter.  The idea behind this parameter is that it should dictate the thread on which the handler runs – either in the context of the caller or in the context of the UI.  Well that attribute, for now, is just a placeholder.  It’s not actually used anywhere, so don’t be surprised if your worker thread raises an event and your subscriber tries to update the UI and gets an exception whining about the use of Control.Invoke.  Again, this is something I intend to complete but when I looked at the options of releasing the framework either earlier with a few missing features or later and feature complete, I thought that just getting it out would be a lot more useful.


Next up: Looking at the performance implications of all of this IoC and DI stuff

Wednesday, March 11, 2009 9:23:45 AM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, March 10, 2009

So I was reading the Windows Mobile Team Blog and to my surprise I saw "How to capture a screen shot with .NET CF" as a topic that actually made it to the top of their "upcoming articles" list.  Seriously?  I know the SDF provides that.  So I did some basic Googling and sure enough, unless you know what you're looking for, it's tough to find (but it's been out for over a year).  For the record, the code is way too simple for a full article.  Even with the P/Invokes directly it's pretty basic, but with the SDF, it looks like this (pulled from a sample web page for our Padarn web server):

// create a bitmap and graphics objects for the capture
Drawing.Bitmap destinationBmp = new Drawing.Bitmap(Forms.Screen.PrimaryScreen.Bounds.Width, Forms.Screen.PrimaryScreen.Bounds.Height);
Drawing.Graphics g = Drawing.Graphics.FromImage(destinationBmp);
GraphicsEx gx = GraphicsEx.FromGraphics(g);

// capture the current screen
gx.CopyFromScreen(0, 0, 0, 0, Forms.Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);

// save the file
destinationBmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png);

// clean house
gx.Dispose();
g.Dispose();
destinationBmp.Dispose();

Simple enough, right?

Tuesday, March 10, 2009 8:59:06 PM (Central Standard Time, UTC-06:00)  #     | 

Articles in this series
Part I: Inversion of Control and the Compact Framework
Part II: The OpenNETCF.IoC Framework: Items and Services (this article)
Part III: The OpenNETCF.IoC Framework: Events
Part IV: The OpenNETCF.IoC Framework: Performance (TBD)

Downloads
Code and Sample available through CodePlex.


The OpenNETCF.IoC Framework

 

Since I don’t expect that everyone has used the SCSF and since the OpenNETCF IoC framework is a very small subset, let’s walk through what it is and how it works.  First, the OpenNETCF.IoC framework is based on the concept of “Components.”  A Component is simply an instance of a class and our framework has two flavors of Components: an Item and a Service.  Generally speaking, the difference between an Item and a Service is that an Item is a uniquely-named instance of a Type (so you can have any number of them provided each instance has a unique name) whereas there can only be one Instance of a service per registered type (it acts somewhat like a Singleton).

Both Items and Services are contained as collections in a root container called the RootWorkItem (a name that comes from the CAB framework).  Let’s take a look more in depth at each of these components and how you might use them together.  For this example we’ll get a little more concrete that the Cars and People example from before, and instead look at classes more actual applications might use.

Items

As I mentioned, Items are simply uniquely named instances of objects.  They can be of any Type – the Items collection doesn’t need to contain only a set of a specific type.  The Items are contained, conveniently enough, in the RootWorkItem.Items collection.  So exactly what advantages to we gain by putting our items in this collection?  The primary benefit is that the RootWorkItem becomes an instance manager and, as we’ll see in a little bit, it can also be a factory.

Let’s assume that our application contains the following Forms: MenuForm, EntryForm and SettingsForm and to make things simple, we’ll assume that they are named with their type name.  If we have these forms in the IoC framework, then any time we need to reference one of them we can simply do something like this:

desiredForm = RootWorkItem.Items[“EntryForm”];

and ta-da, we get the instance of the Form.  We don’t need to pass around a reference to it or store it in some other application global location.  So that’s pretty useful right there.  But the RootWorkItem really is just an application global, right, so it must provide some other benefit.  Well it’s also a factory.  If we want to create the entry form we can use a basic create-and-insert mechanism like this:

EntryForm form = new EntryForm();
RootWorkItem.Items.Add(form, “EntryForm”);

But that really isn’t all that interesting.  Where it gets interesting is that you can let the framework do the construction for you by simply giving it a Type and name (the name is actually optional, as the framework will assign it a GUID if you don’t provide one):

RootWorkItem.AddNew<EntryForm>(“EntryForm”);

That’s handy.  No need to call the object contructor to get an instance and then stuff it into the collection.  Less code is always a good thing.  But what else can it do (right now I’m feeling a bit like Ron Popeil)?

Well that’s not all!  Where it gets fun is in its ability to do injection.  This requires a little more complex of a scenario.  Let’s assume that the MenuForm requires an instance of both an EntryForm and a SettingsForm.  Something like this:

class MenuForm
{
  public MenuForm(EntryForm entryForm, MenuForm menuForm) {…}
}
 

Well the OpenNETCF.IoC framework can actually do these injections for you – all you have to do it provide it a little direction with attributes.  If we simply decorate the constructor with the InjectionConstructor attribute, the framework will search the Items collection for existing items of the proper type to inject.  So the MenuForm looks like this:

class MenuForm
{
  [InjectionConstructor]
  public MenuForm(EntryForm entryForm, MenuForm menuForm) {…}
}

And construction now looks like this:

RootWorkItem.AddNew<SettingsForm>(“SettingsForm”);
RootWorkItem.AddNew<EntryForm>(“EntryForm”);
RootWorkItem.AddNew<MenuForm>(“MenuForm”);

And the magic of the OpenNETCF.IoC framework will inject the first two instances into the third.  An interesting note here is that the Injection Constructor does not have to be public.  The OpenNETCF.IoC framework looks for internal and private constructors as well so you can actually create objects that can only be generated via injection if you wish.

Of course the framework also supports Injection Methods as well, in the event that an InjectionConstructor doesn’t meet your needs:

class MenuForm
{
  public MenuForm() {…}

  [InjectionMethod]
  void InjectEntryForm(EntryForm entryForm) {…}

  [InjectionMethod]
  void InjectSettingsForm(SettingsForm settingsForm) {…}
}

But wait, there’s more!  In the examples so far the RootWorkItem.Items collection must contain the SettingsForm and EntryForm before the MenuForm is created.  Well what if we are lazy and don’t even want to do that?  Well the OpenNETCF.IoC framework can handle that too.  Just add the CreateNew attribute like this:

class MenuForm
{
  [InjectionConstructor]
  public MenuForm([CreateNew]EntryForm entryForm, [CreateNew]MenuForm menuForm) {…}
}

And the framework will create a new instance of the Type if it can’t find it in the Items collection. Construction of all three objects and injecting them now looks like this:

 

RootWorkItem.AddNew<MenuForm>(“MenuForm”);

Extremely simple and clean.

Services

The RootWorkItem also contains a collection of Services.  A Service is very similar to an Item except for the fact that there can only be one service of any given registered type (we’ll covered what “registered” means in a moment).  The collection provides a very similar set of methods and attributes as items.  Again, let’s consider a more concrete example.  Assume your application has a class that handles reading and setting configurations.  There really would only be one instance of this class and in a lot of classic cases people would use the global-wrapped-in-a-new-name called a Singleton.

In the OpenNETCF.IoC framework this would be a service.  Since there can only be one pre registered type, there’s no need to name a Service – the registration type becomes the identifier.  So as a simple construct/add/retrieve a Service operation would look  like this:

Configuration config = new Configuration();
RootWorkItem.Services.Add<Configuration>(config);

Configuration retrievedConfig = RootWorkItem.Services.Get<Configuration>();

As with the Items collection, there is a lot more power and convenience in the framework.  First, we can have the framework do construction for us:

RootWorkItem.Services.AddNew<Configuration>();

Like the Items collection, InjectionConstructor or InjectionMethod attributes can be used to control which constructor for the service class gets called.

The OpenNETCF.IoC framework also offers lazy loading of services, so the service instance isn’t actually created until it is first accessed (instead of when it’s added).

RootWorkItem.Services.AddOnDemand<Configuration>();

We saw earlier that the OpenNETCF.IoC framework would walk the Items collection looking for instances to use during injection.  Well what if an object depends on a Service rather than another Item?  The framework also provides a mechanism for that as well using the ServiceDependency attribute.  So to inject a Service into a consumer class using Constructor Injection it would look like this:

class ServiceConsumer
{
  [InjectionConstructor]
  public ServiceConsumer([ServiceDependency]Configuration config) {…}
}

And of course there is a way to do setter injection instead of constructor injection.  Here it injects into a property instead of using a method like the Items collection:

class ServiceConsumer
{
  public ServiceConsumer() {…}

  [ServiceDependency]
  public Configuration Config { set; get; }
}

And if you want the framework to construct the service if it doesn’t already exist, you simply set the EnsureExists member of the ServiceDependency attribute like this:

[ServiceDependency(EnsureExists=true)]
public Configuration Config { set; get; }

The only other aspect of a Service that an Item does not have is a “registration type”.  This allows you to register a service instance as a type other than its actual base type.  For example you may have a Configuration class that you want to register as a service, but you want to register it as an IConfiguration (this would allow consumers to extract the service by the interface type without ever knowing about or having a reference to the concrete implementation).


Up next: The OpenNETCF.IoC Framework: Event Publication and Subscription

Tuesday, March 10, 2009 7:17:43 AM (Central Standard Time, UTC-06:00)  #     | 
# Monday, March 09, 2009

Articles in this series
Part I: Inversion of Control and the Compact Framework (this article)
Part II: The OpenNETCF.IoC Framework: Items and Services
Part III: The OpenNETCF.IoC Framework: Events
Part IV: The OpenNETCF.IoC Framework: Performance (TBD)

Downloads
Code and Sample available through CodePlex.


Introduction

 

Periodically the software industry goes through a shift in underlying programming practices.  In the 80s the shift was from procedural code to object oriented.  In the 90s we saw the rise of things like “extreme” and “agile” programming.  Recently I’ve seen a shift toward using dependency injection (DI) and inversion of control (IoC).  They’ve been around long enough now that I think they’ll stick, and since any programmer should try to maintain some level of understanding of the latest technologies, I decided to dive into them.

What came out of my investigation were the following:

1.       I was already doing a lot of the stuff, I just didn’t know it

2.       That there really isn’t a reasonable framework in existence for the Compact Framework

3.       Dependency Injection and Inversion of Control, when followed well, can greatly improve extensibility, maintainability and testability of code.

4.       My own IoC framework

Definitions

Before we can talk about all of the benefits of using a framework for Dependency Injection and Inversion of Control, we really need to define them. 

Dependency Injection

Though the name sounds complex, Dependency injection really is what the name implies and is really simple, but explaining it in abstract terms tends to get convoluted.  For example, it could be defined as “with dependency injection you inject dependent objects into the object which depends on them.” Doesn’t really roll of the tongue, does it?  I read that I tend to see “blah, blah, object, blah, depend, blah” and want to move on to something else altogether.  But really, it is simple.  So let’s use an actual example and a picture.

Let’s say we have a couple classes,  Car and Person, and a person can own and drive a car. So it’s something like this:

class Car
{
  public Car() {…}
}

class Person
{
  private Car m_car;

  public Person() {…}

  public void Drive () {…}
}

Now the question here is how does the Drive method “get” or “know” what car to Drive?  One way would be to have the Person instance create the car along these lines:

 

 

public Person()
{
  m_car = new Car();
}


 

So the Person class knows what its dependency is.  It knows at compile time that it needs a Car and creates it.  That’s all well and good, and sure, it work, but it’s certainly not extensible.  To make it a little more extensible, we could use an interface for the Car instead:

 

class Person
{
  private ICar m_car;

  public Person()
  {
    if(this.IsAMoparGuy)

      m_car = new ShinyDodgeChallenger();
    else
      m_car = new RustBucket();
  }
}

 

This is a bit more extensible – the Person has some opportunity to decide what type of car it wants, but it still puts that decision in the Person class and the Person class still has to know about the concrete types of Car. So how do we make it even more extensible so that Person needs to only know about the interface?  Simple – we pass in the object.  That can be done, generally speaking, in two ways.  Either in the constructor:

 

class Person
{
  private ICar m_car;

  public Person(ICar car)
  {
    m_car = car;
  }
}

Or using a method to set it:

 

class Person
{
  private ICar m_car;

  public Person() {}


  public SetCar(ICar car)
  {
    m_car = car;
  }
}

It’s very likely that you’ve used patterns like this in the past, and in fact these are dependency injection.  The first is called “constructor injection” and the second is called “method injection.”  I’ve also seen references to “property injection” which you can probably guess sets the dependency using a Property instead of a method, but a Property really is nothing more than syntactic sugar around a pair of methods.  If you really want to consider it separate, then we can lump the Property and Method injections into something I’ll call “setter injection.”

Inversion of Control

Inversion of Control is a lot like Dependency Injection in that the name puts me off immediately because it sounds like an attempt to use overly large words to describe a likely simple thing, and indeed it is.  In “old school” programming you might have an object (like a Person) that controls another object (like a Car) and when you want to know if some state has changed, you simply query it.

So the Person instance might do something like this

if(m_car.HasCrashed) Call911();

Well Inversion of Control simply turns that around.  Instead of us asking the object for state, the child object (the Car in this example) will inform us of a change.  Sound familiar?  .NET events and delegates are a classic, and really often used, case of Inversion of Control.

So you might hook it up like this

m_car.OnCrash += new CrashHandler(
    delegate { Call911(); }
  );

It’s nothing more complex than that.

IoC and the Compact Framework

When I started out looking into IoC and DI, I was a little put off.  I dislike following programming fads or chasing after some technology simply because it’s all the rage and there are conferences touring the country talking about them.  But I was working on a desktop project and a friend said that I should check out Microsoft’s Smart Client Software Factory (or SCSF) as he thought it would be a good framework to achieve the goals we were after.

Well it turns out that SCSF is built on Microsoft’s Composite UI Application Block (also called CAB) and together they really are just a library that provides a very robust IoC framework.  I’m currenly working on porting that desktop project to use the SCSF and it’s turning out to be very, very useful.

When I needed an IoC framework for the CF, I found that Microsoft’s Patterns and Practices team ported the CAB/SCSF framework a few years back.  I also quickly found out that the people who did the port appeared to do a literal port of the code.  So while it compiles and runs, it certainly does not take into consideration the limited memory and processor power of a typical Windows CE device.  A very common complain about the Mobile Client Software Factory is that its performance sucks.  And I can attest to that.  It does suck.

So what to do?  There are a couple (and really only two that I could find) IoC frameworks that claim to be CF compatible.  I looked at them briefly, but I pretty quickly abandoned them because I really don’t feel like learning the object model for a whole new framework.  I’m using the SCSF and I’m comfortable with it, and I don’t like having to constantly have to think about object models depending on what my code targets.  I also like to keep my code as reusable as possible, and changing frameworks certainly wouldn’t help on that front.

So what I decided to do was to build my own framework based, mostly, on the object model of the SCSF.  The goal was to implement only the bare minimum of what I needed and to build it specifically considering that it would be used on CE devices. What I ended up with is a simple, lightweight dependency injection framework that I called OpenNETCF.IoC. 


Up Next: The OpenNETCF.IoC Framework: Items and Services

Monday, March 09, 2009 12:48:36 PM (Central Standard Time, UTC-06:00)  #     | 
# Monday, January 12, 2009
No idea why the CF omitted the GetCultures method.  The info it returns is clearly supported in the OS, and it's not like it's a lot of work (plus if you're doing globalization, it really is helpful.

Here's a quick implementation I put together this morning that we'll likely add to the SDF:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;

namespace OpenNETCF.Globalization
{
  public class CultureInfoHelper
  {
    private delegate int EnumLocalesHandler(string lpLocaleString);
    private static EnumLocalesHandler m_localesDelegate;
    private static List<CultureInfo> m_cultures;

    private static int EnumLocalesProc(string locale)
    {
      try
      {
        m_cultures.Add(CultureInfo.GetCultureInfo(
        int.Parse(locale, NumberStyles.HexNumber)));
      }
      catch
      {
        // failed for this locale - ignore and continue
      }

      return 1;
    }

    public static CultureInfo[] GetCultures()
    {
      if (m_localesDelegate == null)
      {
        m_cultures = new List<CultureInfo>();
        m_localesDelegate = new EnumLocalesHandler(EnumLocalesProc);
        IntPtr fnPtr = Marshal.GetFunctionPointerForDelegate(
              m_localesDelegate);
        int success = EnumSystemLocales(fnPtr, LCID_INSTALLED);
      }

      return m_cultures.ToArray();
    }

    private const int LCID_INSTALLED = 0x01;
    private const int LCID_SUPPORTED = 0x02;

    [DllImport("coredll", SetLastError = true)]
    private static extern int EnumSystemLocales(
    IntPtr lpLocaleEnumProc, uint dwFlags);
  }
}


Monday, January 12, 2009 12:22:58 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, December 03, 2008
Calling Control.Invoke tends to be a problem, especially for developers who are new to the .NET world.  I think the primary struggle is how to call Invoke without writing a custom delegate, creating a member variable and/or some helper methods.  Here are a couple patterns that I use pretty regularly:

Using an anonymous delegate

if (this.InvokeRequired)
{
   this.Invoke(new EventHandler( delegate (object o, EventArgs a)
   {
     // do your work here
   }));
}
else
{
  
// do your work here
}

Reusing the existing EventHandler

void MyEventHandler(object sender, EventArgs e)
{
   if (this.InvokeRequired)
   {
     this.Invoke(
       new EventHandler(MyEventHandler), new object[] { sender, e }
     );
     return;
   }

   // do your work here
}


Wednesday, December 03, 2008 11:12:37 AM (Central Standard Time, UTC-06:00)  #     | 
# Monday, October 20, 2008
As with most developers, I have a large pool of code snippets from work, tests and investigations I've done in the past.  Sometimes these grow into products, other times they just sit on a hard drive waiting for a time for me to actually use them.

Over the coming weeks I plan to blow the dust off of some of these and see what looks worthwhile.  Simple stuff might get rolled into the SDF (I rolled in a keyboard hook a couple weeks ago) and some stuff will get pushed out as open source libraries because we simply don't need any more products generating any more support load on us at the moment.

Hopefully we'll come up with a coherent place to put all of these in the near future, but for now I'll just post them here on my blog.

The first is the series is called POOMHelper.  I put this together back when WinMo 5.0 first came out while doing work that required that I detect when a POOM item was modified or deleted.  It's a fairly straightforward piece of code that hooks into the eventing mechanism of POOM, plus it also allows you to set some properties of POOM items (mostly Contacts IIRC) that didn't exist in the POOM object model at the time (they may have since been added).

Here's what the public object model looks like:

POOMHelper.PNG

The code is released under our MIT X11 license, so do with it what you wish.  If you need support or help, we offer consulting services.

Download the POOMHelper source here
Download the Interop.PocketOutlook.dll assemly(64 KB) here.
Monday, October 20, 2008 9:44:21 AM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, August 13, 2008
Today I saw two separate posts on pretty much the same question.  How can you determine if the foreground window changes in a WinMo application?  Moreover, how can you determine if the new foreground window is your own, or in some other process?  My initial thoughts were to do some work in the Form's Deactivate event, but that would lead to having to plumb it into every Form, and then you'd still need special case handlers for MessageBoxes and Dialogs and it would be an unmaintainable pain in the ass. I decided to put some time aside this afternoon and see if I could come up with a better solution, and what I came up with is outlined in a new article entitled 'Determining Form and Process Changes in Windows CE'.

Wednesday, August 13, 2008 5:14:58 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, August 01, 2008
It seems that every time I work on a project I get near the end and have to deal with actual deployment of the application and things go south.  Let's face it, Microsoft's wceload application sucks - and that's being generous. It's limited, it's got no object model, and it's behavior has changed over time without any of those changes being documented.

In a recent project I was trying to silently install an application to a directory that would change depending on the target hardware becasue different devices have their storage media named differently.  I wanted to do this without changing or having multiple CAB files, since the application was no different. Achieving this with wceload, I am convinced, is utterly impossible so I put on my reverse-engineering hat, downloaded the CAB spec (cabfmt.doc), and went to work.  Now, a few month later, and with the help of Alex Feinman, we've created a new product called the Windows CE CAB Installer SDK.  In addition to a new product, we went with a new pricing model as well.

The SDK comes with full source,  unit and integration tests designed for running under mstest, samples for generating compressed and uncompressed CAB (the SDK supports both), a template for creating custom installer DLLs and both VB and C# examples of using the SDK.

The main workhorse of the SDK is the WinCEInstallerFIle class, which looks like this:



An example of a custom installer looks like this (just to give you a flavor of how it works):

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using OpenNETCF.Compression.CAB;
using OpenNETCF.Net.MTConnect.Components;
using OpenNETCF.Net.MTConnect.DataItems;

namespace System.Runtime.CompilerServices
{
    public class ExtensionAttribute : Attribute
    {
    }
}
namespace ONCFInstall
{
    public delegate void FileProgressHandler(int progressPercent);
    public static class Extensions
    {
        public static string Find(this List list, string findString)
        {
            foreach (string file in list)
            {
                if (string.Compare(file, findString, true) == 0)
                {
                    return file;
                }
            }
            return null;
        }
    }
    public class CustomCABInstaller : WinCEInstallerFile
    {
        private int m_fileCount = 0;
        private CommandLineArgs m_args;
        public event FileProgressHandler FileProgress;
        public CustomCABInstaller(string cabFileName, CommandLineArgs args)
            : base(cabFileName)
        {
            m_args = args;
            SkipFileNames = m_args.SkipFiles ?? new List();
            PathStringReplacements = m_args.PathStringReplacements ?? new Dictionary();
            SkipOSVersionCheck = m_args.SkipOSVersionCheck;
        }
        // List of file names to skip during installation
        public List SkipFileNames { get; set; } 
        // List of path replacement strings
        public Dictionary PathStringReplacements { get; set; } 
        // If true, the installer will not check to ensure the target meets the installer's version requirements 
        public bool SkipOSVersionCheck { get; set; }

        public override void OnInstallBegin()
        {
            m_fileCount = 0;
        }

        public override void OnTargetOSVersionCheck()
        {
            // check to see if we should skip the OS version check
            if (!SkipOSVersionCheck)
            {
                base.OnTargetOSVersionCheck();
            }
        }

        public override void OnInstallFile(ref FileInstallInfo fileInfo, out bool skipped)
        {
            // check to see if it's a name we should skip
            if (SkipFileNames.Find(fileInfo.FileName) != null)
            {
                Utility.Output(string.Format("Skipping file '{0}'", fileInfo.FileName));
                skipped = true;
                return;
            }

            // do any path replacements
            foreach (KeyValuePair val in PathStringReplacements)
            {
                fileInfo.DestinationFolder = fileInfo.DestinationFolder.Replace(val.Key, val.Value);
            }
            Utility.Output(string.Format("Installing '{0}' to '{1}'", fileInfo.FileName, fileInfo.DestinationFolder));
            base.OnInstallFile(ref fileInfo, out skipped);
            if (FileProgress != null)
            {
                FileProgress((++m_fileCount * 100) / FileCount);
            }
        }
    }
}
Friday, August 01, 2008 2:42:52 PM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, May 19, 2008
We've published a new article on the OpenNETCF Community Site titled "Native vs. Managed Code: GDI Performance"
 
 
In it, I look at the performance differences between native and managed code making GDI calls.
 
In case you missed them, our other recently published articles include:
 
- Performance Implications of Crossing the P/Invoke Boundary
- An Introduction to WCF for Device Developers
- Getting a Millisecond-Resolution DateTime under Windows CE
- Using GDI+ on Windows Mobile
- Sharing Windows Mobile Ink with the Desktop
- OpenNETCF Mobile Ink Library for Windows Mobile 6
- Improving Data Access Performance with Data Caching
- Developing Connected Smart Device Applications with sqlClient
- Debugging Without ActiveSync
- Image Manipulation in Windows Mobile 5.0
- Don't Fear the Garbage Collector
 
All of our articles are available online at:
http://community.OpenNETCF.com/articles
 
Monday, May 19, 2008 11:27:16 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, April 18, 2008

Ever since learning how to use function pointers in C, I've always been a fan of using them to help make code a bit more usable, especially when you've got a state machine.  Today, as I'm working on a Wizard UI for a desktop application I came across a typical scenario for using a function pointer.  Depending on the stage of the Wizard you're in, a button will have to do separate things.

That got me to thinking that most managed developers simply don't understand the power and utility of delegates, but instead simply consider them a necessity when using Control.Invoke or creating custom events. Sure, in my case I could have a switch statement in the click handler and do logic there, or I could unhook the click handler from one method and hook it to another, but those all seem ugly and a pain in the ass to me.  A simple function pointer change is all you need.  So I decided I'd throw together a really simple example of how you would use a delegate to change the behavior of a Button click.

Let's assume that we have a button that we want to click, and when it's clicked it will do one of 4 things, depending on the state of our application.  We'll just use a messagebox here to give you the idea - what it does is up to you- it's a function after all.

public void FunctionA()
{
  MessageBox.Show("FunctionA");
}

public void FunctionB()
{
  MessageBox.Show("FunctionB");
}

public void FunctionC()
{
  MessageBox.Show("FunctionC");
}

public void FunctionD()
{
  MessageBox.Show("FunctionD");
}

To simulate the different "states" I simply added a ListBox (called functionList) to the Form and manually added the function names to it in the Form's constructor.  Sure, I could have used Reflection to be clever and populate the list, but I'm tryiong to keep it simple and show delegates.

functionList.Items.Add("FunctionA");
functionList.Items.Add("FunctionB");
functionList.Items.Add("FunctionC");
functionList.Items.Add("FunctionD");

Alright, so now we know that depending on which item is selected, we want to call one of our four functions.  Since they all have the same interface (and they have to to use a delegate) we simply define a delegate that matches them.  This delegate can be privately scoped inside your class.

delegate void FunctionDelegate();

And then we create an instance variable to hold the current function pointer we want to use:

private FunctionDelegate m_functionPointer = null;

We add an event handler for the SelectedIndexChanged event of the ListBox (in the Form constructor)

functionList.SelectedIndexChanged += new EventHandler(functionList_SelectedIndexChanged);

And implement the event handler.  It simply looks at the newly selected index in the list and changes the value stored in m_functionPointer appropriately.

void functionList_SelectedIndexChanged(object sender, EventArgs e)
{
  // determine which function pointer to store based on selection
  switch (functionList.SelectedIndex)
  {
    case 0:
      m_functionPointer = FunctionA;
      break;
    case 1:
      m_functionPointer = FunctionB;
      break;
    case 2:
      m_functionPointer = FunctionC;
      break;
    case 3:
      m_functionPointer = FunctionD;
      break;
    default:
      m_functionPointer = null;
      break;
  }
}

Next we wire up an event handler for our button (again the the Form constructor):

callButton.Click += new EventHandler(callButton_Click);

And finally the magic and simplicity of the state-dependent call

void callButton_Click(object sender, EventArgs e)
{
  // call our function (as long as it's not null)
  if (m_functionPointer != null)
  {
    m_functionPointer();
  }
}

That's all there is to it.  Run the application, select a function and click the button.

Get the full source here.

Friday, April 18, 2008 5:07:46 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, December 06, 2007

So I picked up a cheap PTZ (pan/tilt/zoom) camera off eBay a couple weeks ago for doing some R&D on a project I'm working on.  My hope was I'd be able to hook it up and talk to it from a device and get streaming video into an app.  Well it turns out that it's not so simple.  All cameras appear to have some form of proprietary interface that obviously varies from OEM to OEM.

I hooked up WireShark in hopes that I could reverse engineer the network commands fromthe packets, but it looks like it would take me weeks to get it figured out, and I don't have that kind of time (or desire) so I shot off an email to the OEM.  While I wait for them to reply (if they ever do) I went about reverse-engineering a kludge.

The device has a built in web server that allows you to control the camera, view video, etc.  So I opened up a page and looked at the source.  It contained a frameset, so I started navigating through frame pages and deconstructing the html to see what commands did what.  Unfortunately the video streaming piece appears to be in a compiled Java applet so getting at that turned out to be a dead-end, however it wasn't a total loss.  I did figure out how to send it commands to pan, tilt and capture single frames (well I figured out a lot more, but I limited my implementation to those functions for now).

So armed with what I knew, I slapped together the following class, basically simulating myself as a browser:

using System;
using System.Net;
using System.Net.Sockets;
using System.Drawing;
using System.IO;
using System.Threading;
using OpenNETCF.Peripherals.Camera;

namespace OpenNETCF.Peripherals
{
  public class MegaTecCamera : ICamera
  {
    private const int CMD_UP = 1;
    private const int CMD_DOWN = 2;
    private const int CMD_LEFT = 3;
    private const int CMD_RIGHT = 4;

    private string m_ip;
    private string m_username;
    private string m_password;

    public MegaTecCamera(IPAddress address, string username, string password)
    {
        m_ip = address.ToString();
        m_username = username;
        m_password = password;
    }

    public Image GetImage()
    {
        Image img = null;

        string command = string.Format(http://{0}/pda.cgi?user={1}&password={2}&page=image&cam=1
            m_ip, m_username, m_password);

        byte[] buffer = new byte[10000];
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(command);
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        using (Stream stream = response.GetResponseStream())
        {
            try
            {
                img = new Bitmap(stream);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Capture failed: " + ex.Message);
            }

            response.Close();
        }
        return img;
    }

    public void Pan(PanDirection direction)
    {
        if (direction == PanDirection.Left)
            SendHttpCommand(GetDirectionCommand(CMD_LEFT));
        else
            SendHttpCommand(GetDirectionCommand(CMD_RIGHT));
    }

    public void Tilt(TiltDirection direction)
    {
        if (direction == TiltDirection.Up)
            SendHttpCommand(GetDirectionCommand(CMD_UP));
        else
            SendHttpCommand(GetDirectionCommand(CMD_DOWN));
    }

    private string GetDirectionCommand(int direction)
    {
        return string.Format(http://{0}/pda.cgi?user={1}&password={2}&page=execute&cam=1&command={3},
            m_ip, m_username, m_password, direction);
    }

    private void SendHttpCommand(string command)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(command);
            try
            {
                request.GetResponse().Close();
            }
            catch { }
        }));
    }
  }
}

The next obvious question is "What the hell do I do with this class that is of any use?"

Well that's the fun part!  I integrated it into a sample page on our demo Padarn server, so we now have images captured from an IP camera streamed back to a 200MHz Windows CE device that in turn serves up those images (and control of the camera) using an ASP.NET server.

The next step I'll add is the ability to turn on and off the light in the room via a web page.

 

Thursday, December 06, 2007 5:15:00 PM (Central Standard Time, UTC-06:00)  #     | 
# Thursday, November 29, 2007
In case you missed it, I published a new article on our community site last week on how to get a DateTime.Now equivalent with the milliseconds field filled in.  Read it here.

Thursday, November 29, 2007 10:20:53 AM (Central Standard Time, UTC-06:00)  #     | 
# Friday, September 28, 2007
Mark has just published a couple articles with just about everything you could want to know about inking:

Using the OpenNETCF Mobile Ink Library for Windows Mobile 6
Sharing Windows Mobile Ink with the Desktop

Friday, September 28, 2007 3:37:14 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, September 06, 2007

So we've already gotten a submission for this month's coding competiton called FlowFx, and I must say it's pretty damned nice.  I'd say this one sets the bar for the quality of what needs to be submitted.

Take a look at the video of the UI in action.

Enter your Windows Mobile or Embedded code for a change to win some cool prizes this month and every month at http://community.opennetcf.com

Thursday, September 06, 2007 5:29:24 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, June 08, 2007

A friend of mine is working on a project that he's been having some major stability problems with.  All of these issues seem to be related with interop to a Sybase database.

After working on and off with him for the past few months, it seems that the root of the problems lie in the fact that a previous developer had written some functions in a "shim" native DLL that calls intoo Sybase, so instead of P/Invoking the Sybase stuff, the developer created a wrapper DLL that he P/Invoked.

After looking at some of the wrapper two things were obvious.  First, the Sybase functions were undecorated C functions, so the shim was unnecessary in the first place, and second, the developer's skill with C are terrible and the shim he created was likely the cause of the problems. So I recommended throwing out the shim, as it was garbage and it was completely unnecessary.

That lead to yet more questions - most notably "how do I marshal X or Y" type things along with "how the hell does one figure this stuff out" and "is this stuff documented anywhere?"  Well other than experience I know of little for figuring it out, and once you get beyond the capabilities of the CF's marshaler I also know of know real documentation.  So I decided I'd put together a fairly simple example of complex marshaling (yes, simple complex).

So first let's look at a typical scenario.  The Sybase stuff often takes in pointers to big, ugly structures.  These structures contain pointers.  Sometimes they are pointers to ASCII strings.  Well instead of wrapping one of these big nasty things, let's create a small representative example that you as a reader can expand upon.

The Native Side

Let's create a native DLL that exports one funtion that takes a fairly easy-to-grasp structure.  The function will simply present a MessageBox with the info.  So here's a structure:

typedef struct MESSAGE_INFO
{
    char *message;
    WORD length;
    DWORD number;
} MESSAGE_INFO;

Note that 'message' is a char *, indicating ASCII.  I'd never write a CE function like this, but this is an example of how to call an existing function, not a best-practices lesson.  Note also that 'length' is only a WORD (2-bytes) making 'number' not DWORD aligned, so there is actually an unused 2 bytes in this thing as well.  Again, I'm trying to show some ugliness that you will see in the wild, not cover how it should be done.

So let's look at the native function just as a reference.  I'll not explain the whole thing as it's simple and the comments should answer most questions:

__declspec(dllexport)
void ShowMessage(MESSAGE_INFO *info)
{
  TCHAR message[512];

  // create a buffer for the Unicode string
  wchar_t *wideString = (wchar_t *)LocalAlloc(LPTR, (info->length + 1) * sizeof(wchar_t));

  // convert the ASCII message to Unicode
  mbstowcs(wideString, info->message, info->length);

  // show a message box with the data
  _stprintf(message, _T("Message: %s\r\nNumber: %i"), wideString, info->number);

  MessageBox(NULL, message, NULL, 0);

  // free the Unicode buffer
  LocalFree(wideString);
}

The Managed Side

Ok, so the native side is pretty straightforward.  It's not ideal from a managed developer's perspective, but let's face it - native developers rarely think of making managed developer's lives easy when they write code.

We need to figure out how to create a MESSAGE_INFO "struct" and pass it in in a format that the API can use it.  First, we can safely rule out letting the CF marshaler handle this.  It would have no clue what to do with this.  We can also rule out creating this as a managed struct.  The interned char * is not blittable, so we'll have to hand-marshal this.  The pointer itself also means we'll have to manage some memory manually too, and that also means "Danger Will Robinson!" as we have the potential for a memory leak.  Don't fear that fact - just be aware of it.

So first, we need to understand what the native DLL is expecting.  It wants a pointer to a struct - so simply put a 4-byte address. At that address will be 12 bytes of data representing a MESSAGE_INFO struct.  The first 4 bytes of that is yet another address.  At that address is ASCII character data.  That's it.  Now lets convert that English to C#.

First we'll create a MESSAGE_INFO class (we choose a class instead of a struct becasue we'll be doing some work internally on it).  In the class we'll define a byte array that holds the 12 bytes that represent a native MESSAGE_INFO as well as some constants for member offsets and lengths for readability:

private const int MESSAGE_PTR_OFFSET = 0;
private const int MESSAGE_PTR_LENGTH = 4;
private const int LENGTH_OFFSET = MESSAGE_PTR_OFFSET + MESSAGE_PTR_LENGTH;
private const int LENGTH_LENGTH = 2;
// DWORD compiler alignment forces an unused 2-byte block here
private const int RESERVED_OFFSET = LENGTH_OFFSET + LENGTH_LENGTH;
private const int RESERVED_LENGTH = 2;
private const int NUMBER_OFFSET = RESERVED_OFFSET + RESERVED_LENGTH;
private const int NUMBER_LENGTH = 4;

public static int StructLength = NUMBER_OFFSET + NUMBER_LENGTH;

// in-memory representation of a native MESSAGE_INFO struct
private byte[] m_data = new byte[StructLength];

So when we call the API, we'll just pass it a byte array (a byte array is already a reference type and will get passes as a pointer) instead of a MESSAGE_INFO struct.  Remember, the native side just wants a 4-byte number.  All of the decorations we use of sturct names and all of that is simply for developer convenience.  As long as we know that our m_data byte array is arranged to match a native MESSAGE_INFO, it will all work.

So our P/Invoke declaration looks like this:

[DllImport("NativeLibrary.dll", SetLastError = true)]
internal static extern void ShowMessage(byte[] messageInfo);

Simple, right?  To call the native API, we simply call ShowMessage with our m_data bytes.  Of course that's a bit ugly and non-managed, so we'll provide an operator to get the m_data without having to expose it explicitly:

// provide an operator to turn a MESSAGE_INFO into a byte array for marshaling
public static implicit operator byte[](MESSAGE_INFO mi)
{
  return mi.m_data;
}

Now we can just call ShowMessage with a managed MESSAGE_INFO instance and we're done.  So far it's all been pretty simple.  The difficult part is actually populating the m_data bytes with the right info. 

First, let's start with an easy one - the numeric data.  The 'number' member is a publicly exported value, while 'length' is meant to be used internally as the length of the string data.  So let's expose a Number property for the managed MESSAGE_INFO class, with set and get accessors.  Instead of using a private member variable to hold the value, we'll hold it in the m_data array:

public int Number
{
  set
  {
    // copy the "value" bytes to our in-memory representation
    Buffer.BlockCopy(BitConverter.GetBytes(value), 0, m_data, NUMBER_OFFSET, NUMBER_LENGTH);
  }
  get
  {
    // get the number from our in-memory representation
    return BitConverter.ToInt32(m_data, NUMBER_OFFSET);
  }
}

Ok, so now the fun one.  The string.  Since we're passing just a pointer, we need to allocate memory for that pointer to "point to" plus we need to make sure that the GC isn't allowed to move that memory around in the event of a compaction.  There are a few ways to do this, but the "recommended" mechanism is a GCHandle. A fixed unsafe pointer would also work, but it assumes you'll only use C# and that you know a bit more about pointers than you might.

So we'll add a GCHandle private member to the class, plus a byte array for our actual message (the memory that the GCHandle will point to):

// GCHandle for our message string
private GCHandle m_messageHandle;

// byte array for the actual message data
private byte[] m_messageData;

Now we need to expose a Message string property.  In the set accessor we want to take the incoming string and put it's ASCII representation into the m_messageData member, get a GCHandle that points to it as m_messageHandle and then stuff that into our m_data.  We also want to make sure that we don't leak if someone sets the message twice.  The get accessor is a lot simpler - it just converts the m_messageData bytes back to a string. So the Message property looks like this:

public string Message
{
  set
  {
    // see if we already have allocated data
    if (m_messageHandle.IsAllocated)
    {
      m_messageHandle.Free();
    }

    // null check for safety
    if (value == null)
    {
      m_messageData = null;
      return;
    }

    // get the ASCII representation of the passed-in value (plus a null terminator)
    m_messageData = Encoding.ASCII.GetBytes(value + '\0');

    // pin it
    m_messageHandle = GCHandle.Alloc(m_messageData, GCHandleType.Pinned);

    // store the address of the pinned object into our 'struct'
    IntPtr dataPointer = m_messageHandle.AddrOfPinnedObject();
    byte[] pointerBytes = BitConverter.GetBytes(dataPointer.ToInt32());
    Buffer.BlockCopy(pointerBytes, 0, m_data, MESSAGE_PTR_OFFSET, MESSAGE_PTR_LENGTH);

    // store the length
    short length = (short)m_messageData.Length;
    Buffer.BlockCopy(BitConverter.GetBytes(length), 0, m_data, LENGTH_OFFSET, LENGTH_LENGTH);
  }
  get
  {
    // only return a string is something is allocated
    if (m_messageHandle.IsAllocated)
    {
        // create a string, stripping the null terminator
        return Encoding.ASCII.GetString(m_messageData, 0, m_messageData.Length).TrimEnd(new char[] {'\0'});
    }
    else
    {
        return null;
    }
  }
}

Lastly we need to make sure our class itself doesn't leak when it's destroyed.  My solution is simple - a Finalizer:

~MESSAGE_INFO()
{
  // free the GCHandle if necessary
  if (m_messageHandle.IsAllocated)
  {
    m_messageHandle.Free();
  }
  m_messageData = null;
}

Yes, implementing Dispose might be a better way to go, but this is less code, and again we're looking at marshaling, not implementing best practices (and I see nothing wrong with a Finalizer for this anyway).

That's it.  You're done.  When run, you'll get something like this:

Download the full solution source here (note I included several SDKs and built and tested with one you probably don't have, so you might need to hack up the project file if it complains).

Friday, June 08, 2007 1:18:23 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, May 16, 2007

Problem
I have some fairly complex data I want to put into a list.  I'd like to use different fonts, icons and maybe even some custom lines and polygons.  Unfortunately the ListBox control in the CF pretty much sucks for this type of thing.  What can the SDF do for me?

Solution
Yes, the default ListBox control is a bit challenged, but all hope is not lost.  The OpenNETCF.Windows.Forms.ListBox2 follows the desktop model and provides owner-drawn capabilities.  Here are some screen shots of a sample application we have for the ListBox2 as well as some of the OpenNETCF.Net networking classes.

   

As you can see, we're drawing items with different font sizes, colors and weights on both screens, plus we're adding some icons in each item in the second and I have that nice and ugly custom "selected" color.

Download the full sample (NetUI) here.

Wednesday, May 16, 2007 6:14:46 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, May 03, 2007

Problem
I've got a text file on the device that's stored in [ASCII/Unicode]. Sure, I can create a System.IO.Stream derivative, read the data and close it, but I'd like something simpler. What can the SDF do for me?

Solution
The OpenNETCF.IO.FileHelper class provides some useful methods to explore.  Take a look at these snippets:

string fileContents;
fileContents = OpenNETCF.IO.FileHelper.ReadAllText("MyASCIIFile.txt", Encoding.ASCII);
fileContents = OpenNETCF.IO.FileHelper.ReadAllText("MyUnicodeFile.txt", Encoding.Unicode);

string[] linesOfTextFile;
linesOfTextFile = OpenNETCF.IO.FileHelper.ReadAllLines("MyASCIIFile.txt", Encoding.ASCII);
linesOfTextFile = OpenNETCF.IO.FileHelper.ReadAllLines("MyUnicodeFile.txt", Encoding.Unicode);

Thursday, May 03, 2007 12:45:49 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, April 20, 2007

Problem A
I have an application that transfers data to another app via (serial/CAN/Ethernet/can-and-string/cheese stream ion a macaroni pipe/whatever).  I have set up a send and acknowlege paradigm so I know when the receiver has all of the data, but I need to know that what the other end received is correct.  What does the SDF do for me?

Problem B
I have an application that receives a file from a native application.  The application send me a 'checksum' along with the data and the native guys tell me that I must use that checksum value to make sure that the data I received has not been corrupted.  I vaguely understand what a checksum is, but I have no clue how to calculate one from the file.  What does the SDF do for me?

Solution
[Tested on a custom PXA270-based Windows CE 5.0 device *and* the desktop (full framework 2.0)]

Nicely enough, the SDF solves both of these with the use of the OpenNETCF.CRC class. The CRC (short for Cyclic Redundancy Check) class supports generating a CRC for a byte array or a FileStream.

Here's what usage for a file looks like.  This creates a 32-bit checksum (we support 8-64 bit) using a standard ploynomial (we support any custom polynomial too):

FileStream fs = File.OpenRead(sourceFileName);
uint checksum = (uint)OpenNETCF.CRC.GenerateChecksum(fs, 32, (ulong)OpenNETCF.CRCPolynomial.CRC_CCITT32);
fs.Close();

 

Friday, April 20, 2007 1:40:28 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, January 10, 2007

Bugs are frustrating, but when you write code for a living you expect them and live with them as a fact of life.  They are a lot harder to swallow when they are introduced by other libraries, especially when those libraries work counter to what you would expect.  It's even more frustrating when it's in a library like the Compact Framework itself.

Recently we got a bug report for our ConnectionManager in some code that I know we tested - basically the Description returned by the DestinationInfo class was returning odd data and concatenating to it did bad things.  Experience told me that it sounded like the data coming back from the native API was not getting properly truncated at a NULL.  Not an unusual mistake, so I went to find it.

Description = Marshal2.PtrToStringUni(baseAddr, 16, 256);
int nullPos = Description.IndexOf('\0'
);
if (nullPos > -1) Description = Description.Substring(0, nullPos);

The bad news was the code looked right - we were looking for NULL and trimming at it.  The only way a problem could arise is if the buffer was non-zero at the start.  So off to look at that code.  Here's where the allocation is made:

hDestInfo = Marshal.AllocHGlobal(DestinationInfo.NativeSize);

Again, it looked right.  However, talking with Alex Feinman he said that the Marshal Alloc functions do no zero memory.  In the earlier versions of this code we used our internal MarshalEx, which P/Invoked LocalAlloc with the LPTR parameter, which zeros everything at allocation.  Why the hell the CF doesn't do that one can only guess, but it makes no sense in my book.  Who would want to allocate memory and not zero it?  Worse still is that MSDN doesn't say that the memory is not zeroed.

So then, changing from our MarshalEx function to the CF's Marshal function introduced an error.  So how do we fix it?  There's no CF equivalent to a memset (again, this is a WTF in my book, but there are a few language limitations like this that irritate me - try taking an IntPtr and turning the data at that location into a managed struct without having to copy it).

So anyway, I looked at coredll.def from Platform Builder 5.0 to see if coredll.dll helps, and sure enough I see this:

malloc @1041
calloc @1346
_memccpy @1042
memcmp @1043
memcpy @1044
_memicmp @1045
memmove @1046
memset @1047

P/Invoke to the rescue.  I added the following to the SDF (so it will be in the next release).  Note that wile I was there I handles the annoyances of not having a way to copy from an IntPtr to an IntPtr (memcpy) or a way to validate IntPtrs (IsBad[Read/Write]Ptr) while I was at it.

public static void SetMemory(IntPtr destination, byte value, int length)
public static void SetMemory(IntPtr destination, byte value, int length, bool boundsCheck)
public static void Copy(IntPtr source, IntPtr destination, int length)
public static void Copy(IntPtr source, IntPtr destination, int length, bool boundsCheck)
public static bool IsSafeToWrite(IntPtr destination, int length)
public static bool IsSafeToRead(IntPtr source, int length)

Then a simple fix back in the ConnectionManager:

hDestInfo = Marshal.AllocHGlobal(DestinationInfo.NativeSize);
Marshal2.SetMemory(hDestInfo, 0, DestinationInfo.NativeSize, false);

 

Wednesday, January 10, 2007 8:51:46 PM (Central Standard Time, UTC-06:00)  #     | 
# Monday, January 08, 2007

There's a thread in the newsgroups where someone is trying to show a Notification before his app does some long-running process. Here's an example of how it's done.

  1. Create a WM 5.0 Windows app, then add a reference to 'Microsoft.WindowsCE.Forms'.
  2. Add a single Button to the Form and name it 'workButton'
  3. Add this to the top of the code page:

    using System.Threading;
    using Microsoft.WindowsCE.Forms;

  4. Replace the entire non-designer Form class code with this:

    public partial class Form1 : Form
    {
      public Form1()
      {
        InitializeComponent();
        workButton.Click += new System.EventHandler(workButton_Click);
      }

      delegate void EventDelegate();

      Notification m_workNotify = new Notification();
      Control m_invoker = new Control();
      EventDelegate m_workCompleteDelegate;

      private void workButton_Click(object sender, EventArgs e)
      {
        // disable the button so it can't be clicked again until work is done
        workButton.Enabled = false;
        m_workCompleteDelegate = new EventDelegate(OnWorkComplete);

        Thread workThread = new Thread(new ThreadStart(WorkProc));
        m_workNotify.Text = "I'm doing important stuff";
        m_workNotify.Caption = "Please wait...";
        m_workNotify.InitialDuration = 5;

        m_workNotify.Visible = true;

        workThread.Start();
      }

      void OnWorkComplete()
      {
        // re-enable the button
        workButton.Enabled = true;
      }

      void WorkProc()
      {
        // simulate working
        Thread.Sleep(20000);
        m_invoker.Invoke(m_workCompleteDelegate);
      }
    }

Monday, January 08, 2007 1:51:27 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, December 06, 2006

We got a request today from someone wondering if the SDF would help send a Wake-on-LAN or Magic Packet.  Well I've never had to do it before, so I looked it up on Wikipedia. The short answer is no, but that's because all of the required pieces are already there in the CF.

Here's my guess on it - keep in mind that I don't have a WOL-capable PC lying around to test this with (if you test it and can confirm if it does or does not work, by all means let me know).

UPDATE (Dec 7, 06): Alex Feinman took the time to test the original code and the broadcast didn't work.  The code has been updated with working, tested code.

/// <summary>
/// Wakes a remote PC
/// </summary>
/// <param name="targetMAC">MAC address of target. Must be 6 bytes and MUST be in network order (reversed)</param>
/// <param name="password">Optional password. Must be null or 4 or 6 bytes.</param>
public static void WOL(byte[] targetMAC, byte[] password)
{
  // target mac must be 6-bytes!
  if (targetMAC.Length != 6)
  {
    throw new ArgumentException();
  }

  // check password
  if((password != null) && 
      (password.Length != 4) && 
      (password.Length != 6))
  {
    throw new ArgumentException();
  }

  int packetLength = 6 + (20 * 6);
  if (password != null)
  {
    packetLength += password.Length;
  }

 
byte
[] magicPacket = new byte[packetLength];

  // has a 6-byte header of 0xFF
  byte[] header = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  Buffer.BlockCopy(header, 0, magicPacket, 0, header.Length);

  // repeat the destination MAC 16 times

  // your MAC *is* in network (reverse) order, right??
 
int
offset = 6;
  for(int i = 0 ; i < 16 ; i++)
  {
    Buffer.BlockCopy(targetMAC, 0, magicPacket, offset, targetMAC.Length);
    offset += 6;
  }

  if (password != null)
  {
    Buffer.BlockCopy(password, 0, magicPacket, offset, password.Length);
  }

  IPEndPoint ep = new IPEndPoint(IPAddress.Broadcast, 9);
  UdpClient c = new UdpClient();
 
c.Send(magicPacket, magicPacket.Length, ep);
}

Wednesday, December 06, 2006 4:29:35 PM (Central Standard Time, UTC-06:00)  #     | 
# Friday, August 25, 2006

If you read much of what I write, you know that performance is something I like to always keep in mind, and I'm also a big fan of quantitative analysis.  It all started ages ago with a look at the real time capabilities of Windows CE, but most recently I've been looking at managed code.  This entry is the second in a series of looks at performance of managed code, specifically the .NET Compact Framework.  For the first entry, see this blog entry (which became this MSDN article).

Act II - Method calls are Expensive (or Stay in the Shallow End of the Stack!)

As with many of my diatribes into technical problems, this all started with a newsgroup post.  SOmeone posted that the had done a Towers of Hanoi implementation in VB.NET, C# and C++ and that the C# implementation was faster than VB, but got slower in CF 2.0.  They also said that native code was much faster than both (I think he may have said an order of magnitude, but don't quote me on that).

Well he didn't post any code so we could reproduce his results, and I never take anyone on their word on something like this, so I decided to put it to the test.  Before going any further, you may need some background information on what the Towers of Hanoi problem is.  You're probably familiar with it - you just didn't know what it was called.  Go read this Wikipedia entry and come back.

I decide to do a recursive solution, so the meat of the problem is that we have an exponential number of method calls, making the call stack very, very deep.  Just from a memory point of view this is a bad idea (see my MEDC presentation on memory management if you want to know more on the whys of that).  But you'll also see that the expense of method calls in the CF (see Act I) really bites you here as it bites hard.

First, let's look at the code.  In C#, it looks like this:

public class Hanoi
{
  private int[] pegs = new int[3];

  public Hanoi(int totalDisks)
  {
    // start with all disks on peg 0
    pegs[0] = totalDisks;
    pegs[1] = 0;
    pegs[2] = 0;
  }

  public int Solve()
  {
    int et = Environment.TickCount;
    Move(0, 2, 1, pegs[0]);
    return Environment.TickCount - et;
  }

  private void Move(int fromPeg, int toPeg, int intermediatePeg, int disks)
  {
    if(disks == 0) return;

    // move all but one disk to the intermediate peg
    Move(fromPeg, intermediatePeg, toPeg, disks - 1);

    // move the last remaining disk to the destination - no need for the intermediate
    pegs[fromPeg] -= 1;
    pegs[toPeg] += 1;

    // now move all but one off the intermediate peg to the destination peg
    Move(intermediatePeg, toPeg, fromPeg, disks - 1);
  }
}

You can see that Move calls itself twice.  Now try tracing the code in your head if I call Solve when totalDisks is 30.  Ugly.

Now lets look at the C++ implementation.

class Hanoi
{
    private:
        int pegs[3];
        void Move(int fromPeg, int toPeg, int intermediatePeg, int disks);

    public:
        Hanoi(int totalDisks);
        int Solve();
};

Hanoi::Hanoi(int totalDisks)
{
    // start with all disks on peg 0
    pegs[0] = totalDisks;
    pegs[1] = 0;
    pegs[2] = 0;
}

void Hanoi::Move(int fromPeg, int toPeg, int intermediatePeg, int disks)
{
    if(disks == 0) return;

    // move all but one disk to the intermediate peg
    Move(fromPeg, intermediatePeg, toPeg, disks - 1);

    // move the last remaining disk to the destination - no need for the intermediate
    pegs[fromPeg] -= 1;
    pegs[toPeg] += 1;

    // now move all but one off the intermediate peg to the destination peg
    Move(intermediatePeg, toPeg, fromPeg, disks - 1);
}

int Hanoi::Solve()
{
    int et = GetTickCount();
    Move(0, 2, 1, pegs[0]);
    return GetTickCount() - et;
}

You can see that it's really not much different - in fact it's really, really close.  So what do we see for results when we run these? Look at the table below (my device was an Axim X30 with a PXA270 processor)

disks C# - CF 2.0 C++ Diff % improvement
20 744 461 283 38%
21 1518 1148 370 24%
22 2997 2068 929 31%
23 5964 4006 1958 33%
24 11892 7646 4246 36%
25 23942 14875 9067 38%
26 47945 29423 18522 39%
27 95674 58496 37178 39%
28 190917 116837 74080 39%

The C++ version performed nearly 40% better.  Of course the C# JIT compiler is running on a mobile device, with presumably much less power than a desktop machine, so the JITter is built to optimize for compile speed, not execution speed.  To try to level the playing field, I compiled the C++ version in Debug mode to turn off all compiler optimizations.  I can't actually see what the CF JITter creates for assembly, so we can't be sure if the resulting code is the same, but that's the nearest I can come.

So we know that the implementation code is near identical.  We also know from Act I that identical code in a single method has no performance difference between native and managed code.  We also know from Act I that method calls are quite expensive.  A reasonable conclusion then is that the performance degradation we're seeing here is nearly all in the cost of method calls.  Does this mean that managed code performance is terrible?  The answer is "it can be if you don't fully understand what the CLR is doing." The lesson learned here then is to either refactor the algorithm to keep your call stack short (there are non-recursive solutions to this problem - maybe another day I'll test that), or put heavily recursive stuff into a native library and P/Invoke to it.

If you want to try these out on your own device, you can download the source code here (post your results in the comments if you'd like).  The source actually points out another lesson, this time in UI development speed. The C# version has a nice UI that I put together in about 10 minutes.  Writing a nice UI would have taken quite a bit longer in C++ so I didn't even bother. With the C++ version you have to get the results from by running in eVC or Studio and setting a breakpoint in the calling loop and writing down the number after each iteration.

Friday, August 25, 2006 11:09:58 AM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, August 23, 2006

We've had an idea for a new project for some time, and we've finally decided to put out a code seed for it to see if the community wants to get involved.

The idea is this - Create a native coredll.dll library for the desktop that exactly matches the one exposed by Windows CE (same funtions at the same ordinals).  In theory, this would allow you to run Compact Framework applications against the full framework including code that P/Invokes.  The long-term goal is to implement every funtion (there are about 1800 of them, we've seeded the project with 50), but the milestone I'm shooting for is to get this library to a point that the SDF will run on the desktop.

Why would you want this library you ask?  The answer is fairly simple - to help in debugging and unit testing.  I don't envision you shipping a product that runs on CE and XP, but I do see great value in being able to run your CF assemblies through NUnit or Team Suite unit tests, which today cannot be done on a device.  This project is an enabler for that.

THe project is located at CodePlex as the OpenNETCF Advanced Debugging Toolkit.  Look for more pieces to the toolkit as time progresses.

Wednesday, August 23, 2006 1:00:11 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, August 22, 2006

The Bitmap class in the Compact Framework is a confusing thing, largely because it has abstracted what the OS is doing underneath a little too far.  For example, look at the following code:

Bitmap bmp1 = new Bitmap(fileStream);
Bitmap bmp2 = new Bitmap(200, 200);

Let's assume that fileStream is a valid stream to a resource bitmap file that is 100x100 in size.  So is there any difference between bmp1 and bmp2, other than the fact bmp1 presumably has some color data in it?  The answer is yes - there's a very big difference, and that difference can have a huge impact on application performace as well as cause exceptions.

So let's look at this a little deeper with some examples.  Here's the first:

int iterations = 0;

while (true)
{
  try
  {
    iterations++;
    Bitmap b = new Bitmap(GetImageStream());
    if (iterations % 100 == 0)
    {
      Debug.WriteLine(string.Format("{0} objects", iterations));
    }
  }
  catch
  {
    Debug.WriteLine(string.Format("Failed after {0} objects", iterations));
    Debugger.Break();
  }
}

If I run this code (GetImageStream() just pulls an image from an embedded resource), the app will run forever, occasionally spitting out the debug port how many hundreds of objects it's created.  If you run RPM on it you'll see memory getting allocated, the GC firing occasionally and resources being freed up.  All is well in the world of managed code and everything is working as expected.  Hooray.

Now let's change that ever so slightly to this:

int iterations = 0;

while (true)
{
  try
  {
    iterations++;
    Bitmap b = new Bitmap(200, 200); // <--- CHANGED HERE
    if (iterations % 100 == 0)
    {
      Debug.WriteLine(string.Format("{0} objects", iterations));
    }
  }
  catch
  {
    Debug.WriteLine(string.Format("Failed after {0} objects", iterations));
    Debugger.Break();
  }
}

Note the single change where the bitmap is created.  Try running this and after a few iterations - the exact number depends on available device memory - it will OOM (throw an out of memory exception).  On the device in front of me it was about 40.

So the first thing to do is theorize why this would happen.  Seems like the Bitmap's resources aren't getting freed after it goes out of scope at the end of the while block.  An explicit call to Dispose() may solve it if that's the case, so let's try another test.

int iterations = 0;

Bitmap b = null;
while (true)
{
  if (b != null)  // explicit disposal
    b.Dispose();

  try
  {
    iterations++;
    b = new Bitmap(200, 200);
    if (iterations % 100 == 0)
    {
      Debug.WriteLine(string.Format("{0} objects", iterations));
    }
  }
  catch
  {
    Debug.WriteLine(string.Format("Failed after {0} objects", iterations));
    Debugger.Break();
  }
}

Sure enough, when we run this, it behaves like the first.  Strange that the Bitmap behaves differently depending on which constructor we use - this is contrary to common sense, right? 

So let's think a little more.  A Bitmap has a large area of unmanaged resources and some managed resources.  It seems that when we create a bitmap using the size ctor, the finalizer doesn't get run when an OOM happens.  Let's test again and see if that really is what's going on. We'll remove the explicit Dispose call and wait for the finalizers and try again when we OOM.

int iterations = 0;

while (true)
{
  try
  {
    iterations++;
    Bitmap b = new Bitmap(200, 200);
    if (iterations % 100 == 0)
    {
      Debug.WriteLine(string.Format("{0} objects", iterations));
    }
  }
  catch (OutOfMemoryException)
  {
    Debug.WriteLine("Waiting for finalizers to run..."));
    GC.WaitForPendingFinalizers();
    Bitmap b = new Bitmap(GetImageStream());
  }
}

When we run this one, again all is well in managed code land, though we see it waiting for finalizers to run a lot, and that catch is an expensive one for perf (as all exceptions are). At this point I think "well that surely has to be a bug" but I often like a second opinion, so I went right to the source and asked the CF team about the behavior.  The response from them is actually quite informative.  Their response in in italics below.

I think you are probably seeing is several interactions that can be quite confusing.

  1. Creating a bitmap using the stream constructor will construct a DIB (Device Independent Bitmap).
  2. Creating a bitmap using the width/height constructor will construct a DDB (Device Dependent Bitmap).
  3. DIB's are allocated out of the virtual address space of the application.
  4. DDB's are allocated by the driver. This typically means that they are allocated in the virtual address space of gwes.exe. Alternatively, the driver could allocate these in dedicated video ram.
  5. Creating a bitmap with the stream constructor will generate a fair amount of garbage as it copies data from one buffer to the other.

When we perform a GC because of an OOM in the stream constructor case, we will almost certainly have some amount of garbage that we can free back to the OS immediately. This will also trigger the finalizer to run on another thread as soon as possible. That should help the next call to bitmap creation.

When we perform a GC because of an OOM in the width/height constructor case, it is fairly likely that the OOM is caused because of virtual memory exhaustion in gwes.exe. Thus freeing memory in our process will not help the memory condition in gwes.exe. We need the bitmap finalizer to run before this would actually free memory in a way that would help this scenario. While the finalizer thread would certainly have been triggered to start, it most likely will not get a chance to free bitmaps before we OOM while trying to allocate a bitmap immediately after triggering a GC on the initial thread.

In short, we have 2 different types of Bitmap in our runtime with varying performance and allocation characteristics. DDBs are generally faster to manipulate and draw to the screen than DIBs, but they are constructed in an external memory space that can cause allocation confusion and cause the performance of calls to LockBits or Save to be slow. If a DIB is desired and you wish to construct it based on width and height, we provide a function that constructs a Bitmap with a width, height, and pixelformat specified. This function will construct a DIB instead of a DDB.

I personally still consider this a bug in the implementation - the CF should catch these occasions and handle it for us rather than OOMing all the way back to the app to wait for the Finalizers and retry - that's an implementation that should be done below us. 

Still the answer sheds light on the fact that how we create a Bitmap should be highly dependent on how we intend to use that Bitmap.

Tuesday, August 22, 2006 1:24:50 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, June 29, 2006

Since most people like to try before they buy, we've released Evaluation Versions of our Calendar Controls.  Download the evaluation binaries and a sample project using them here.

Thursday, June 29, 2006 11:37:14 AM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, June 27, 2006

First let me go on record as saying that I think using a 'z' to terminate words is utterly moronic, like using the number 2 instead of the word 'to'.

Anyway, on 2 my skillz....

Last week I posted a fantastic kludge for turning on the Bluetooth radio on an Axim X30.  Well, like any kludge, as soon as it shipped it broke.  Turns out the notification icon isn't always in the rightmost position - it can move.  That screwed with my intricate algorithm of moving in and up 10 pixels from the lower left corner of the screen.

So what's a developer to do?  First, let's take a quick detour into how those icons work. 

They "tray" icons are actually called Notification icons and they are displayed by calling the Shell_NotifyIcon API.  When the icon is created you provide a window handle for it to notify when it's clicked.  The icon itself doesn't have any other abilities.  This is a critical piece of info for this hack.

Since I know it's posting messages to another Window when it's clicked, I simply needed to figure out exactly what it's doing.  Time to break out Remote Spy++ in eVC (are you in the group that never really knew what the hell that tool was used for? This is a classic case).

Loaded up Spy++ and I see a Window conspicuously named "Bluetooth Console" - that's promising.  I put a watch on it and sure enough, when I tap the icon, messages get posted to that window (off is in the blue box, on in the red).  Now all I need to do is post the same messages.

So first, I need the handle for that Window.  Time for the FindWindow P/Invoke:

IntPtr btWindow = FindWindow("WCE_BTTRAY", "Bluetooth Console");

Next, replicate the messages the tap generates:


SendMessage(btWindow, WM_USER + 1, 0x1267, 0x201);
SendMessage(btWindow, WM_USER + 1, 0x1267, 0x202);
SendMessage(btWindow, WM_USER + 1, 0x1267, 0x200);

That causes the Bluetooth Console to create and show the popup menu. Now it needs a message to tell it to wait for a menu tap:

SendMessage(btWindow, WM_ENTERMENULOOP, 0x01, 0x00);

Now "generate" the tap:

SendMessage(btWindow, WM_COMMAND, BluetoothRadioState ? CMD_BT_OFF : CMD_BT_ON, 0x00);

And tell it to quit listening for menu taps:

SendMessage(btWindow, WM_EXITMENULOOP, 0x01, 0x00);

It does something else that I can't tell what the effect is, but since it's doing it, I will too:

// not sure what this does, but physically clicking does it, so replicate it here
SendMessage(btWindow, WM_USER + ((BluetoothRadioState) ? (uint)0xC00D : 0xC00C), 0x01, 0x00);

And finally get the Menu window and hide it:

IntPtr btmenu = FindWindow("MNU", "");

SendMessage(btmenu, WM_DESTROY, 0x00, 0x00);
SendMessage(btmenu, WM_CANCELMODE, 0x00, 0x00);

While it's still ugly, it's a bit cleaner than the original, and much smaller.  This is our new class in its entirety:

using System;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace OpenNETCF.Devices
{
  public static class AximX30
  {
    public static bool BluetoothRadioState
    {
      get
      {
        RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WIDCOMM\BtConfig\General");
        bool currentState = (((int)key.GetValue("StackMode")) == 1);
        key.Close();
        return currentState;
      }
      set
      {
        // see if any action is needed
        if (BluetoothRadioState == value)
        {
          return;
        }

        IntPtr btWindow = FindWindow("WCE_BTTRAY", "Bluetooth Console");

        // pop up the menu
        SendMessage(btWindow, WM_USER + 1, 0x1267, 0x201);
        SendMessage(btWindow, WM_USER + 1, 0x1267, 0x202);
        SendMessage(btWindow, WM_USER + 1, 0x1267, 0x200);

        // give it time to create the menu
        System.Threading.Thread.Sleep(100);

        // find the menu that popped up
        IntPtr btmenu = FindWindow("MNU", "");

        // start the window listening for menu messages
        SendMessage(btWindow, WM_ENTERMENULOOP, 0x01, 0x00);
        // send it the on or off message
        SendMessage(btWindow, WM_COMMAND, BluetoothRadioState ? CMD_BT_OFF : CMD_BT_ON, 0x00);
        // tell it it's done listening
        SendMessage(btWindow, WM_EXITMENULOOP, 0x01, 0x00);

        // not sure what this does, but physically clicking does it, so replicate it here
        SendMessage(btWindow, WM_USER + ((BluetoothRadioState) ? (uint)0xC00D : 0xC00C), 0x01, 0x00);

        // now hide the menu
        if (btmenu != IntPtr.Zero)
        {
          SendMessage(btmenu, WM_DESTROY, 0x00, 0x00);
          SendMessage(btmenu, WM_CANCELMODE, 0x00, 0x00);
        }

        return;
      }
    }

    [DllImport("coredll.dll")]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("coredll.dll")]
    private static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

    private const uint WM_DESTROY = 0x02;
    private const uint WM_CANCELMODE = 0x1F;
    private const uint WM_USER = 0x400;
    private const uint WM_ENTERMENULOOP = 0x0211;
    private const uint WM_EXITMENULOOP = 0x0212;
    private const uint WM_COMMAND = 0x0111;

    private const int CMD_BT_OFF = 0x1001;
    private const int CMD_BT_ON = 0x1002;

  }
}

Tuesday, June 27, 2006 2:58:19 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, June 23, 2006

I recently worked on a project that required me to connect to a printer from a Pocket PC with the Widcomm bluetooth stack on it.  Frustrating as it was, one positive thing came from it - I generated a nice start to a set of classes for using High-Point Software's BTConnect.

Of course it means that you'll need to buy BTConnect to use this library without the "evaluation mode" popup, but it abstracts the ugliness of sommand-line parameters away from the developer so you can focus on creating your app.

I've parked the library here:

www.opennetcf.org/shared

Friday, June 23, 2006 3:31:35 PM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, June 05, 2006

I may be a little biased because they're ours, but our new Calendar Controls really are the best looking ones I've seen.  You can now add a calendar to your managed app that looks just like the Outlook calendar.

Monday, June 05, 2006 12:30:35 PM (Central Daylight Time, UTC-05:00)  #     | 

Seems like it took forever, but we've finally released the SDF 2.0 Extensions for Visual Studio 2005.

For more info on what exatly comes with the new SDF Extensions, click here.

Monday, June 05, 2006 12:26:58 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, May 30, 2006

Just as a mental exercise, today I decided to try to write a single method that would allow me to return information about the currently running assembly as a string.  One method needed to return the copyright info, the company info, etc.

The end result is this simple function:

public string GetAssemblyAttribute<T>(T attributeType) where T:Type
{
    object attribute = Assembly.GetExecutingAssembly().GetCustomAttributes((T)attributeType, false)[0];
    return (string)attribute.GetType().GetProperties()[0].GetValue(attribute, null);
}

And calling it is this easy:

string s = "";

s = GetAttribute(typeof(AssemblyCopyrightAttribute));
s = GetAttribute(typeof(AssemblyCompanyAttribute));
s = GetAttribute(typeof(AssemblyDescriptionAttribute));
s = GetAttribute(typeof(AssemblyProductAttribute));
s = GetAttribute(typeof(AssemblyTitleAttribute));
s = GetAttribute(typeof(AssemblyTrademarkAttribute));

Now why it has to be this ugly I'm not sure, but isn't reflection a hoot!? 

Tuesday, May 30, 2006 9:12:52 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, May 11, 2006

For those who attended any of my sessions at MEDC, below are links to the downloads.

SumoRobot Lab Manual
SumoRobot Sample Code
HeapTest RPM Test App
CF RPM provisioning file for WM 5.0

Thursday, May 11, 2006 5:38:12 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, May 09, 2006

In one of the hands-on labs here at MEDC a developer asked how to pass a managed funtion to a native DLL as a callback function.  I promised him a sample, so here's a simple one that shows how to call EnumWindows:

 

public delegate int EnumWindowsProc(IntPtr hwnd, IntPtr lParam);

public partial class Form1 : Form
{
    EnumWindowsProc callbackDelegate;
    IntPtr callbackDelegatePointer;

    [DllImport("coredll.dll", SetLastError = true)]
    public static extern bool EnumWindows(IntPtr lpEnumFunc, uint lParam);

    public Form1()
    {
        InitializeComponent();

        callbackDelegate = new EnumWindowsProc(EnumWindowsCallbackProc);
        callbackDelegatePointer = Marshal.GetFunctionPointerForDelegate(callbackDelegate);

        EnumWindows(callbackDelegatePointer, 0);
    }

    public int EnumWindowsCallbackProc(IntPtr hwnd, IntPtr lParam)
    {
        System.Diagnostics.Debug.WriteLine("Window: " + hwnd.ToString());

        return 1;
    }
}

Tuesday, May 09, 2006 7:44:10 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, February 23, 2006

If you're building a CE image and want to include CF 1.0 or CF 2.0, then it's pretty simple - just drag the component from the catalog into your workspace.  But what if you don't want to include the CF at all, but still have the plumbing there so your end-user can install the CF themselves and have it work?  One could look through the cesysgen.bat files and decipher what needs to be set or, if you're lazy like me, you could ask the CF team.

Here's the answer, courtesy of Jim Suplizio:

The appropriate support sysgen will have to be added to the image depending on what version of CF is going to be installed.

  • SYSGEN_DOTNET_SUPPORT is the CF 1.0 support sysgen.
  • SYSGEN_DOTNETV2_SUPPORT is the CF 2.0 support sysgen. SYSGEN_DOTNETV2_SUPPORT is a super-set of the CF 1.0 support.

Effectively if SYSGEN_DOTNETV2_SUPPORT is added to the image then the end user can deploy either 1.0 or 2.0 and all of the required underlying CE OS pieces will be there.

Keep in mind that required means "base functionality". CF 2.0 has optional functionality that requires other SYSGENS and they are as follows:

  • Message Queuing - SYSGEN_MSMQ
  • Soap Reliable Messaging Protocol - SYSGEN_MSMQ_SRMP
  • SQLMobile (2005) requires CoCreateGuid functionality - SYSGEN_OLE_GUIDS
  • IPv6 - SYSGEN_TCPIP6
  • IE, PIE, HTMLView (htmlview.dll) or nothing - SYSGEN_IE, SYSGEN_PIE, SYSGEN_HELP or simply nothing.
  • The following only apply to the MainstoneII, other devices will only have null driver sets:
    • D3D Mobile - BSP_D3DM_XSCALE
    • D3D Mobile - SYSGEN_D3DMXSCALE

 

Thursday, February 23, 2006 3:47:21 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, February 22, 2006

It's been a while since we visited the OpenNETCF.Deskop.Communication library, but there have been lingering issues that ActiveSync 4.x have exposed (a stack imbalance exception).  So today I revisited the library and did some fixes to it as well as to the sample app (bad, bad me for not marshaling calls to the UI from a thread.  It's now a Studio 2005 project.

The latest code is in Vault and the downloads on the site are updated to this new version (2.9) as well.

Wednesday, February 22, 2006 1:09:33 PM (Central Standard Time, UTC-06:00)  #     | 
# Sunday, February 19, 2006

SDF 2.0 continues to have functionality for working with the time and time zones for devices.  The differences from SDF 1.x are a namespace change, a classname change (don't believe the beta docs or the beta, these have changed since that drop), and under the hood a lot more internal checks are going on to head off errors and to provide correct device support.  Basically this one has been pretty heavily tested across a broad range of devices.

Some quick highlights:

Getting and Displaying a List of Time Zones

using OpenNETCF.WindowsCE;
...
// get and display all available zones
TimeZoneCollection tzc = new TimeZoneCollection();
tzc.Initialize();

foreach (TimeZoneInformation tzi in tzc)
{
    lstZones.Items.Add(tzi);
}

Displaying the Currently Set Time Zone

using OpenNETCF.WindowsCE;
...
// get and display the currrent zone

TimeZoneInformation currentTz = new TimeZoneInformation();
DateTimeHelper.GetTimeZoneInformation(ref currentTz);
lblCurrentZone.Text = currentTz.StandardName;

Setting the Current Time Zone (from the Listing above)

using OpenNETCF.WindowsCE;
...
if
(lstZones.SelectedItem != null)
{
    TimeZoneInformation tzi = (TimeZoneInformation)lstZones.SelectedItem;
    DateTimeHelper.SetTimeZoneInformation(tzi);

    // this verifies that the time zone did indeed get changed
    TimeZoneInformation tz = new TimeZoneInformation(
        (byte[])Registry.LocalMachine.OpenSubKey("Time").GetValue(
            "TimeZoneInformation"));
    MessageBox.Show("Current Timezone in Registry is:\r\n" 
        + tz.StandardName, "Verified");
}

Displaying the Current Time (without DateTime.Now)

using OpenNETCF.WindowsCE;
...
DateTime dt = DateTimeHelper.SystemTime;

txtHour.Text = dt.Hour.ToString();
txtMinute.Text = string.Format("{0:00}", dt.Minute);
txtSecond.Text = string.Format("{0:00}", dt.Second);

Setting The Current System Time (Local Time is Analogous)

using OpenNETCF.WindowsCE;
...
// get the current time so we can copy the date part

DateTime dt = DateTimeHelper.SystemTime;

DateTimeHelper.SystemTime = new DateTime(dt.Year, dt.Month, dt.Day,
    int.Parse(txtHour.Text), int.Parse(txtMinute.Text), int.Parse(txtSecond.Text));

 

Sunday, February 19, 2006 5:17:03 PM (Central Standard Time, UTC-06:00)  #     | 
# Sunday, February 12, 2006

CE supports a Multimedia timer, though it's not in CF 1.0 or 2.0.  We've rectified that in SDF 2.0 (though your platform must support the Multimedia timer to use it - meaning WM and PPC are out).

So what do high-performance timers buy you?  Well if you look at how a regular timer works, they run at a really low priority and are horrible if you want anything that resembles deterministic behavior.  If you set the interval to say 1000ms, it's guaranteed to not fire in less than 1000ms, but there's actually no upper bound at all.  Jitter of 50ms (5%) would not be exceptional and in fact I've seen substantially worse on systems with a high load.

Our Timer2 class (name is still not finalized, so don't finalize on it) is based on the desktop's Timer class and provides things like a one-shot capability (timer fires once and never again without you having to disable it) and if you derive from it you can have it run a callback instead of raising an event.

Here's a quick example of usage:

void StartMyOneshotTimer
{
  // create a timer
  Timer2 oneShot = new Timer2();

  // make it a one-shot timer
  oneShot.AutoReset = false;

  // fire 3 seconds from enabling
  oneShot.Interval = 3000;

  // allow 10ms latitude for when it fires
  // so it will fire between now + 2995 and now + 3005
  oneShot.Resolution = 10;

  oneShot.Elapsed += new ElapsedEventHandler(oneShot_Elapsed);

  oneShot.Start();
}

void oneShot_Elapsed(object sender, ElapsedEventArgs e)
{
  // do something here
}

Sunday, February 12, 2006 1:39:02 PM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, February 04, 2006

You might have noticed that SDF 2.0 no longer has serial or GPS classes.  This is intentional.  CF 2.0 now has serial classes and the Windows Mobile AKU includes GPS support.  We realize that there are some of you out there that are using GPSes on non-WM 5.0 devices and that you'd like to be able to use our stuff under Studio 2005.  For those people, we've spun the Serial and GPS classes into a stand-alone assembly: OpenNETCF.IO.Serial.  There are no plans for an installer for this assembly, and unless we get strong feedback it probably won't make it into the SDF either.

Saturday, February 04, 2006 1:41:38 PM (Central Standard Time, UTC-06:00)  #     | 
# Thursday, February 02, 2006

If you're a Windows CE device developer and you've got a device with a persistent registry, you're probably already aware that the CF Registry class doesn't help much for saving the registry, restoring branches from a file or creating volatile keys.  Once again the SDF is here to help with CreateVolatileSubkey, RestoreHiveBasedKey, RestoreRamBasedRegistry, SaveHiveBasedKey and SaveRamBasedRegistry.

One note - the doc says they're in the Registry2 class - that's already been changed to RegistryHelper.

 

Thursday, February 02, 2006 10:31:28 PM (Central Standard Time, UTC-06:00)  #     | 
# Sunday, January 29, 2006

Making apps power aware, especially through the device Power Manager works, but the code is kind of ugly and a pain to implement.  Once again SDF 2.0 simplifies things:

using System;
using System.Windows.Forms;
using OpenNETCF.WindowsCE;

namespace WindowsCETest
{
  public partial class MyPowerAwareClass
  {
    public MyPowerAwareClass()
    {
      DeviceManagement.DeviceWake +=
       new DeviceNotification(
DeviceManagement_DeviceWake);

      PowerManagement.PowerUp += new DeviceNotification(PowerManagement_PowerUp);
    }

    void PowerManagement_PowerUp()
    {
      MessageBox.Show("The Power Manager says I'm awake!");
    }

    void DeviceManagement_DeviceWake()
    {
      MessageBox.Show("Device notifications say I'm awake!");
    }
  }
}

Sunday, January 29, 2006 8:56:53 AM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, January 28, 2006

The Windows CE operating system supports several notifications for common device events liek changes in AC power, network status changes and time changes.  They are exposed by using the CeRunAppAtEvent or CeSetUserNotification APIs.  While the Windows Mobile Notification Broker provides an interface for some of these, it doesn't provide access to all of them, nor is it available for general Windows CE developers.

SDF 1.4 provided a set of Notification classes that could be used to get these (and those classes are still there in SDF 2.0) but we felt that a simple object model around these would really be a nice thing to have.  So we created the OpenNETCF.WindowsCE.DeviceManagement class.  Now subscribing to the notifications is as simple as this example of detecting when the device time has been modified:

using System;
using System.Windows.Forms;
using OpenNETCF.WindowsCE;

namespace WindowsCETest
{

public class MyClass
{

public MyClass()
{

    DeviceManagement.TimeChanged +=
       
new DeviceNotification(DeviceManagement_TimeChanged);
}

void
DeviceManagement_TimeChanged()
{
    MessageBox.Show(
"The time was just changed.");
}

}

}

Saturday, January 28, 2006 5:26:51 PM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, January 21, 2006

We're extremely close to a beta release of SDF 2.0.  To give you a taste of what's in it, we've posted the online documentation.  Any feedback is appreciated.  Enjoy.

Saturday, January 21, 2006 10:49:17 PM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, December 20, 2005

So if you're working with Microsoft's new Microsoft.WindowsMobile.PocketOutlook namespace and trying to use the OutlookCollection.Restrict method to filter by a Contact's (or any PimItem's) ItemId field, you will likely run into a problem.

First, let me say the ItemID Class sucks.  It exposes basically nothing useful but a ToString() method, even though it holds numeric data.  And the first item added to POOM gets the ItemId of 0x80000001, which you might note is an *unsigned* number (again, the CLS is a pain for not allowing unsigned numbers).  So if you have an ItemId class and you want to use it, you have to do something like this:

unchecked
{
    int myId = int
.Parse(m_outlookSession.Contacts.Items[0].ItemId.ToString())
}

Really, that's how you have to do it.

So, let's say we have a Contact's ItemId and we want to see if the current session has said Contact.  One might try this:

m_outlookSession.Contacts.Items.Restrict("[ItemId]=" + itemId.ToString());

A nice try, but that gives you the not-so-helpful exception:

The query string is incorrectly formatted.
Parameter name: [ItemId]=-2147483647

Alright, so ItemId only exposes itself as a string, and Restrict has little in the way of useful documentation or samples, so maybe we can try it as a string like so:

m_outlookSession.Contacts.Items.Restrict("[ItemId]='" + itemId.ToString() + “'“);

Well that gives a similar exception, just adding the single quotes:

The query string is incorrectly formatted.
Parameter name: [ItemId]=-'2147483647'

Because I've used POOM from C++, I know that ItemId seems new to me, so just as a lark I figure I'll try 'Oid' as a field name instead, and keep it as a numeric:

m_outlookSession.Contacts.Items.Restrict("[Oid]=" + itemId.ToString());

Lo and behold, success!

Now technically this might not be a true bug, but it's sure not documented anywhere, nor would it be at all intuitive to guess if you'd not used C++ to access an IContact (which exports an Oid field, *not* an ItemId) before.  Bad Windows Mobile Team.  BAD!

Things needed:

  • The ItemID needs to have an explicit operator for conversion to an int at the very least.  A ToInt32 or ToIntPtr or something of the sort would be useful.
  • Either name the field Oid like it's stored in the database, or provide some sort of substitution so when I filter by ItemId the underlying class converts that to Oid.
  • The least they could have done was give exception text like “The field cannot be found in the collection“
  • Documenting how to remove a Restrict once set would be useful (I used Restrict(“[Oid]<>0“) for lack of any better idea)
Tuesday, December 20, 2005 9:15:43 PM (Central Standard Time, UTC-06:00)  #     | 
# Friday, December 09, 2005

The final version of my article on deployment has been published on MSDN.

Friday, December 09, 2005 6:52:37 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, November 23, 2005

I was playing around with PlaySound today (no pun intended) and was kind of surprised to find that I could play an embedded resource wave file with one line of code (well one line past the P/Invoke declaration):

using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

....

// P/Invoke declarations....
[DllImport("CoreDll.DLL", EntryPoint="PlaySound", SetLastError=true)]
private extern static int PlaySound(byte
[] szSound, IntPtr hMod, SoundFlags flags);

[Flags]
enum SoundFlags
{
  Alias = 0x00010000,
  Filename = 0x00020000,
  Synchronous = 0x00000000,
  Asynchronous = 0x00000001,
  Memory = 0x00000004,
  Loop = 0x00000008,
  NoStop = 0x00000010
}

...

PlaySound(((MemoryStream)Assembly.GetExecutingAssembly(
  ).GetManifestResourceStream(
  "AudioTest.tada.wav")).GetBuffer(),
  IntPtr.Zero,
  SoundFlags.Synchronous | SoundFlags.Memory);

Wednesday, November 23, 2005 11:41:54 AM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, November 22, 2005

A couple new articles from OpenNETCF have finally gone public:

Device Debugging and Emulation in Visual Studio 2005 from Alex Feinman
Using Visual Studio 2005 to Design User Interfaces and Data for Device Applications from Maarten Struys

Tuesday, November 22, 2005 12:02:12 PM (Central Standard Time, UTC-06:00)  #     | 
# Sunday, August 21, 2005

Here's yet another article I'm working on for MSDN and again, comments are welcome.  A printer friendly version is here.  The source is available here.

Sunday, August 21, 2005 11:16:38 PM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, August 15, 2005

Here's another article I'm working on for MSDN.  Again, comments are welcome.  A printer friendly version is here.  The source is available here.

Monday, August 15, 2005 8:25:29 PM (Central Daylight Time, UTC-05:00)  #     | 
# Sunday, August 14, 2005

Here's a draft of an article I'm putting together for MSDN.  Comments are welcome.  A printer friendly version is here.

Sunday, August 14, 2005 11:20:26 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, August 05, 2005

Finally!  We've released SDF 1.4.  What's new you ask?  Well here's a quick list (which I extracted from check-in comments from the source Vault - you can do the same to see exactly what the changes are):

  • Bluetooth support added
  • Serial.GPS mods to standardize naming
  • Diagnostics.DebugMessage and RetailMessage
  • Bug fixes in TimeZoneCollection and DateTimeEx
  • Bug Fix in XmlSerializer for GUIDs
  • EventWaitHandle.WaitOne bug fix
  • Additions and fixes for AccessPoint and Adapter classes
  • Bug fix in StreamInterfaceDriver.DeviceIoControl
  • ThreadEx.RealTimePrioority added
  • Updated BatteryLife designer
  • Updated DateTimePicker Designer
  • Fixes and Updates to Win32Window
  • ApplicationEx fix for modal Forms and thread safety added
  • FTP bug fixes
  • ControlEx added support for WM_COMMAND
  • DeviceMonitor adds RequestDeviceNotifications
  • SelectedIndexChanged fix in ComboBoxEx
  • WS and WS_EX updated to remove unsupported styles
Friday, August 05, 2005 9:57:21 AM (Central Daylight Time, UTC-05:00)  #     | 

I often start on a project with the best of intentions to finish, but then something else comes up and I get side tracked.  I was going through code this morning and came across one such example from when I was doing the Travelling Salesman Problem on a device.  Someone on a newsgroup said a device wasn't powerful enough to do it - I thought that was BS, so I sat down and started coding.  Of course then other things came up and this ended up unfinished (though it's probably only a day of work away).  I did get far enough to do Help documentation for it.

Knowing myself and the list of things I need to do, I'm probably not going to get back to it any time soon, so if someone else wants the mental exercise, feel free to finish what I've done.

Friday, August 05, 2005 9:39:44 AM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, August 04, 2005

Someone asked me today “How do I get my CF window to not show up in the taskbar?”  Since Form.ShowInTaskbar isn't supported in the CF, I decided to play around and see how it's done.

It led me to play around with the SDF's Win32Window and EnumEx classes.  Basically, populate a couple ListViews with all the available style and extended style bits, then let the user check whatever s/he wants and reapply them.

187 lines of code later and I've got a very busy window (check out the caption bar) but it's still in the Taskbar.  Turns out to be not-so-easy after all - so I'll keep trying, but here's a quick sample on using the Win32Window.

Here's the meat of it:

private void ParentWindow_Load(object sender, System.EventArgs e)

{

      m_child.Show();              

      m_childWindow = Win32Window.FindWindow(null, "ChildWindow");

     

      WS childStyle = m_childWindow.Style;

 

      foreach(WS style in EnumEx.GetValues(typeof(WS)))

      {

            ListViewItem lvi = new ListViewItem(style.ToString());

            lvi.Checked = ((childStyle & style) != 0);

           

            lvwWS.Items.Add(lvi);

           

      }

 

      WS_EX childExStyle = m_childWindow.ExtendedStyle;

 

      foreach(WS_EX exstyle in EnumEx.GetValues(typeof(WS_EX)))

      {

            ListViewItem lvi = new ListViewItem(exstyle.ToString());

            lvi.Checked = ((childExStyle & exstyle) != 0);

           

            lvwWSEX.Items.Add(lvi);

      }

 

}

 

private void btnSetStyle_Click(object sender, System.EventArgs e)

{

      WS style = 0;

      foreach(ListViewItem lvi in lvwWS.Items)

      {

            if(lvi.Checked)

                  style |= (WS)EnumEx.Parse(typeof(WS), lvi.Text);

      }

      m_childWindow.Style = style;

 

      WS_EX exstyle = 0;

      foreach(ListViewItem lvi in lvwWSEX.Items)

      {

            if(lvi.Checked)

                  exstyle |= (WS_EX)EnumEx.Parse(typeof(WS_EX), lvi.Text);

      }

      m_childWindow.ExtendedStyle = exstyle;

      m_child.Refresh();

}

PostScript:

It turns out this is right.  If you modify the style of the Form during it's contructor, then it will not show up in the Taskbar (thanks Sergey).

public ChildWindow()

{

      InitializeComponent();

 

      Capture = true;

      Win32Window hwnd = Win32Window.GetCapture();

      Capture = false;

 

      hwnd.ExtendedStyle |= WS_EX.NOANIMATION;

}

 

PostPostScript:

This uses SDF 1.4, so if you're trying it, make sure you get the latest code (or wait a day until 1.4 is released)

 

Thursday, August 04, 2005 3:27:09 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, April 26, 2005

It seems that mobile and embedded computing is finally being recognized as an actual career path.  Purdue University has a class and a Mobile Computing Lab.  Check out the projects students have done so far.  Very promising indeed.

Tuesday, April 26, 2005 8:54:33 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, March 25, 2005

For those of you who may ever need to interface to a DS1307 I2C real time clock (it would wourk for the 1306 SPI RTC as well) here's a useful class.

private class RTCTime
{
 private byte[] m_bytes = new byte[7];
 
 public RTCTime()
 {
 }
 public RTCTime(byte[] data)
 {
  m_bytes = data;
 }
 public RTCTime(DateTime dateTime)
 {
  this.Second = dateTime.Second;
  this.Minute = dateTime.Minute;
  this.Hour = dateTime.Hour;
  this.Day = dateTime.Day;
  this.Month = dateTime.Month;
  this.Year = dateTime.Year;
 }
 public static implicit operator byte[](RTCTime rtc)
 {
  return rtc.m_bytes;
 }
 public static implicit operator RTCTime(byte[] bytes)
 {
  return new RTCTime(bytes);
 }
 public static explicit operator DateTime(RTCTime rtc)
 {
  return new DateTime(rtc.Year, rtc.Month, rtc.Day, rtc.Hour, rtc.Minute, rtc.Second, 0);
 }
 public int Second
 {
  get { return BCD_TO_WORD(m_bytes[0]); }
  set { m_bytes[0] = WORD_TO_BCD(value); }
 }
 public int Minute
 {
  get { return BCD_TO_WORD(m_bytes[1]); }
  set { m_bytes[1] = WORD_TO_BCD(value); }
 }
 public int Hour
 {
  get { return BCD_TO_WORD(m_bytes[2]); }
  set { m_bytes[2] = WORD_TO_BCD(value); }
 }
 public int DayOfWeek
 {
  get { return BCD_TO_WORD(m_bytes[3]); }
  set { m_bytes[3] = WORD_TO_BCD(value); }
 }
 public int Day
 {
  get { return BCD_TO_WORD(m_bytes[4]); }
  set { m_bytes[4] = WORD_TO_BCD(value); }
 }
 public int Month
 {
  get { return BCD_TO_WORD(m_bytes[5]); }
  set { m_bytes[5] = WORD_TO_BCD(value); }
 }
 public int Year
 {
  get { return BCD_TO_WORD(m_bytes[6]); }
  set { m_bytes[6] = WORD_TO_BCD(value); }
 }
 public int Length
 {
  get { return m_bytes.Length; }
 }
 private int BCD_TO_WORD(byte x)
 {
  return (x & 0x0f) + ((x >> 4) * 10);
 }
 private byte WORD_TO_BCD(int x)
 {
  return (byte)((x % 10) + ((x / 10) * 0x10));
 }
}
Friday, March 25, 2005 10:36:30 AM (Central Standard Time, UTC-06:00)  #     | 
# Saturday, March 12, 2005

Pocket PC magazine has published an article by Mick Badran of Breeze Training that uses the SDF (though they called it the Smart Device Extensions - remember back when the CF was called that?).  An online version is available here.

Saturday, March 12, 2005 3:53:55 PM (Central Standard Time, UTC-06:00)  #     | 
# Monday, February 21, 2005

I'm working on a fairly straightforward wrapper for a customer and it occurred to me that there are a distinct lack of simple working examples of the “more difficult” marshaling techniques in the CF. A classic example is a native struct that contains a pointer to a string. On the desktop it's simple (and in CF 2.0 it's pretty easy too), but in CF 1.0, it's not straightforward.

Personally I don't mind the code required to do the marshaling - in fact I think everyone using marshaling should be required to understand these fundamentals. While that's never going to happen, some people still are interested, or their project may necessitate being able to do it, and of course having a sample never hurts.

So consider the following very simple struct. A simgle 4-byte integer followed by a pointer to a string:

typedef struct
{
 INT IntMember,
 LPSTR StringMember
} MYSTRUCT, *PMYSTRUCT;

What appears to be rather simple in C - just a mere 5 lines of code - expands to the following not-so-small 80-line code base in C#:

public class EmbeddedStringPtrStruct
{
 // offsets used internally
 private const int intMemberOffset = 0;
 private const int stringMemberOffset = 4;
 // this is the actual struct data to be passed to native methods
 protected byte[] m_bytes = new byte[8];
 // private var to hold string data pointer
 private IntPtr m_pStringMember = IntPtr.Zero;
 // default public ctor
 public EmbeddedStringPtrStruct()
 {
 }
 // dtor - call Dispose if the consumer didn't
 ~EmbeddedStringPtrStruct()
 {
  this.Dispose();
 }
 // operator to get a byte array used for marshaling
 // this allows you to pass the EmbeddedStringPtrStruct directly
 public static implicit operator byte[](EmbeddedStringPtrStruct esps)
 {
  return esps.m_bytes;
 }
 // accessor for INT member
 public int IntMember
 {
  get
  {
   return BitConverter.ToInt32(m_bytes, intMemberOffset);
  }
  set
  {
   byte[] bytes = BitConverter.GetBytes(value);
   Buffer.BlockCopy( bytes, 0, m_bytes, intMemberOffset, 4 );
  }
 }
 public string StringMember
 {
  get
  {
   IntPtr ptr = (IntPtr)BitConverter.ToInt32( m_bytes, stringMemberOffset );
   return MarshalEx.PtrToStringUni(ptr);     
  }
  set
  {
   // first see if we already have one allocated
   if(! m_pStringMember.Equals(IntPtr.Zero))
   {
    MarshalEx.FreeHGlobal(m_pStringMember);
   }
   // alloc storage for the string so we can pass the ptr
   m_pStringMember = MarshalEx.StringToHGlobalUni(value);
   // convert to an Int32 and get the bytes
   byte[] bytes = BitConverter.GetBytes( m_pStringMember.ToInt32() );
   // stuff it into the global
   Buffer.BlockCopy( bytes, 0, m_bytes, stringMemberOffset, 4 );    
  }
 }
 public void Dispose()
 {
  // clean up native memory allocations
  if(! m_pStringMember.Equals(IntPtr.Zero))
  {
   MarshalEx.FreeHGlobal(m_pStringMember);
  }
 }
}

See, not so bad, is it?

Monday, February 21, 2005 9:14:39 PM (Central Standard Time, UTC-06:00)  #     | 
# Friday, February 04, 2005

So I started a amanged wrapper for Pocket Excel some time ago - probably a year and a half now.  I made good progress - got it so you can real and write workbooks, worksheets, cells - just no support for the formulas yet.  Then I got sidetracked with one thing after another. 

Initially I was going to use it as a commercial product to get revenue to support OpenNETCF, but I honestly don't have the time for it.  If I can find someone, or a group of someones willing to put in a final push to finish it (maybe an industrious student looking for thesis material?) I'll donate it to the community at large as an OpenNETCF namespace.

Any takers?

Friday, February 04, 2005 8:07:39 PM (Central Standard Time, UTC-06:00)  #     | 
# Tuesday, December 21, 2004

If you're a CF developer READ THIS ARTICLE.  Once done, read it again. 

Tuesday, December 21, 2004 7:48:03 PM (Central Standard Time, UTC-06:00)  #     | 
# Wednesday, November 10, 2004

If you follow by blog, you've probably noticed one of my side projects is moving toward a device driver with managed code.  Why?  Because most any sane person will tell you it's either not possible or a bad idea.  But hey, I always want to know the why behind those statements.  “It will be too slow.”  Well, how slow, exactly?  “It won't be deterministic.”  What if I don't need it to be, or what if I can get around that axiom?

Well as a new motivator I had someone ask about using the SPI bus on an Applied Data Systems device using C#.  It's a slow bus, and determinism isn't really necessary, so this would be a classic opportunity.  Add to that the fact they don't need to to be a tru driver running under the auspices of device.exe - simply controlling the bus from their app is fine.

So last night I sat down and hammered out a general purpose physical address accessor class, which I'll post below and add to the SDF.  Then today I did a quick implementation test with it just to see how it does.  I didn't do the SPI driver because 1. it would take a while and 2. they need to understand how it works and it will do them some good to write it.  What I did do is use the class to control a GPIO on the PXA255 which is connected to an LED on my board.  This provided a quick visual check that I was indeed able to set the GPIO register values.  It also allowed me to use a scope to see how fast it would go.

Well, as a test I put it in a tight loop toggling the LED state as fast as possible, just a while(true) {on, off } kind of thing, and I did the same logic in a pure C app.  The C app had pulse durations ~500ns, plus or minus a pretty large margin because I didn't fiddle with thread priorities or anything.  The C# app had pulse durations ~1us.  So you can look at it glass-half-empty and say wow, it's twice as slow as native code, or glass-half-full and say, wow, that's well below millisecond resolution and quite suitable for a lot of stuff.

I love managed code.

//==========================================================================================
//
// OpenNETCF.IO.PhysicalAddressPointer
// Copyright (c) 2004, OpenNETCF.org
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the OpenNETCF.org Shared Source License.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the OpenNETCF.org Shared Source License
// for more details.
//
// You should have received a copy of the OpenNETCF.org Shared Source License
// along with this library; if not, email
licensing@opennetcf.org to request a copy.
//
// If you wish to contact the OpenNETCF Advisory Board to discuss licensing, please
// email
licensing@opennetcf.org.
//
// For general enquiries, email
enquiries@opennetcf.org or visit our website at:
//
http://www.opennetcf.org
//
//==========================================================================================
using System;
using System.Runtime.InteropServices;

namespace OpenNETCF.IO
{
 /// <summary>
 /// This class is used to access memory mapped addresses
 /// !!! DANGER WILL ROBINSON !!  You can cause serious problems using this class without knowing what you're doing!
 /// We reiterate the statement in our license that OpenNETCF provides absolutely no warranty on this code and you use it at your own risk
 /// </summary>
 public class PhysicalAddressPointer
 {
  // use 4k pages
  private const uint PAGE_SIZE  = 0x1000;

  // consts from winnt.h
  private const uint MEM_RESERVE  = 0x2000;
  private const uint PAGE_NOACCESS = 0x0001;
  private const uint PAGE_READWRITE = 0x0004;
  private const uint PAGE_NOCACHE  = 0x200;
  private const uint PAGE_PHYSICAL = 0x400;
  private const uint MEM_RELEASE  = 0x8000;

  private IntPtr m_virtualAddress = IntPtr.Zero;
  private IntPtr m_addressPointer = IntPtr.Zero;

  /// <summary>
  /// An accessor class to a physical memory address.
  /// </summary>
  /// <param name="physicalAddress">Physical Address to map</param>
  /// <param name="size">Minimum size of the desired allocation</param>
  /// <remarks>The physical address does not need to be aligned as the PhysicalAddressPointer will handle alignment
  /// The size value will aligned to the next multiple of 4k internally, so the actual allocation may be larger than the requested value</remarks>
  public PhysicalAddressPointer(uint physicalAddress, uint size)
  {
   m_addressPointer = MapPhysicalAddress(physicalAddress, size);
  }

  ~PhysicalAddressPointer()
  {
   if(m_virtualAddress != IntPtr.Zero)
   {
    VirtualFree(m_virtualAddress, 0, MEM_RELEASE);
   }
  }

  /// <summary>
  /// Write an array of bytes to the mapped physical address
  /// </summary>
  /// <param name="bytes">data to write</param>
  public void WriteBytes(byte[] bytes)
  {
   Marshal.Copy(bytes, 0, m_addressPointer, bytes.Length);
  }

  /// <summary>
  /// Write a 32-bit value to the mapped address
  /// </summary>
  /// <param name="data">data to write</param>
  public void WriteInt32(int data)
  {
   Marshal.WriteInt32(m_addressPointer, data);
  }

  /// <summary>
  /// Write a 16-bit value to the mapped address
  /// </summary>
  /// <param name="data">data to write</param>
  public void WriteInt16(short data)
  {
   Marshal.WriteInt16(m_addressPointer, data);
  }

  /// <summary>
  /// Write an 8-bit value to the mapped address
  /// </summary>
  /// <param name="data">data to write</param>
  public void WriteByte(byte data)
  {
   Marshal.WriteByte(m_addressPointer, data);
  }

  /// <summary>
  /// Read a series of bytes from the mapped address
  /// </summary>
  /// <param name="length">number of bytes to read</param>
  /// <returns>read data</returns>
  public byte[] ReadBytes(int length)
  {
   byte[] bytes = new byte[length];
   Marshal.Copy(m_addressPointer, bytes, 0, length);
   return bytes;
  }

  /// <summary>
  /// Read a 32-bit value from the mapped address
  /// </summary>
  /// <returns>read value</returns>
  public int ReadInt32()
  {
   return Marshal.ReadInt32(m_addressPointer);
  }

  /// <summary>
  /// Read a 16-bit value from the mapped address
  /// </summary>
  /// <returns>read value</returns>
  public short ReadInt16()
  {
   return Marshal.ReadInt16(m_addressPointer);
  }

  /// <summary>
  /// Read an 8-bit value from the mapped address
  /// </summary>
  /// <returns>read value</returns>
  public byte ReadByte()
  {
   return Marshal.ReadByte(m_addressPointer);
  }

  IntPtr MapPhysicalAddress(uint physicalAddress, uint size)
  {
   uint alignedAddress = 0;
   uint offset   = 0;
   uint alignedSize  = 0;
   IntPtr returnAddress = IntPtr.Zero;
   
   
   // get a page aligned address
   alignedAddress = PageAlignAddress(physicalAddress);
   offset = physicalAddress - alignedAddress;

   // get a page aligned size
   alignedSize = RoundSizeToNextPage(size + offset);

   // reserve some virtual memory
   m_virtualAddress = VirtualAlloc(0, alignedSize, MEM_RESERVE, PAGE_NOACCESS);

   // sanity check
   if(m_virtualAddress == IntPtr.Zero)
   {
    // allocation failure!
    return IntPtr.Zero;
   }

   
   // Map physical memory to virtual memory
   if(VirtualCopy (m_virtualAddress, (IntPtr)(alignedAddress >> 8), alignedSize,
    PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL) == 0)
   {
    // copy failure!
    VirtualFree(m_virtualAddress, 0, MEM_RELEASE);

    return IntPtr.Zero;
   }

   // offset and return
   return new IntPtr(m_virtualAddress.ToInt32() + offset);
  }

  // simply aligns an address to a page boundary to prevent data aborts and fun stuff like that
  uint PageAlignAddress(uint addressToAlign)
  {
   return addressToAlign & ~(PAGE_SIZE -1);
  }

  // allocations must be made in page multiples. 
  // this method finds the next multiple given a desired size
  uint RoundSizeToNextPage(uint size)
  {
   return (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
  }

  // p/invoke declarations
  [DllImport("coredll.dll", EntryPoint="VirtualAlloc", SetLastError=true)]
  private static extern IntPtr VirtualAlloc(uint lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

  [DllImport("coredll.dll", EntryPoint="VirtualCopy", SetLastError=true)]
  private static extern int VirtualCopy(IntPtr lpvDest, IntPtr lpvSrc, uint cbSize, uint fdwProtect);

  [DllImport("coredll.dll", EntryPoint="VirtualFree", SetLastError=true)]
  private static extern int VirtualFree(IntPtr lpAddress, uint dwSize, uint dwFreeType);
 }
}

 

Wednesday, November 10, 2004 2:28:34 PM (Central Standard Time, UTC-06:00)  #     | 
# Monday, October 18, 2004

Yesterday I fought with getting the ListView to have CheckBoxes that didn't “automagically” toggle whenever you tapped an item, but only when the checkbox itself was clicked.  Well, not to be outdone, I've got it working (rather well actually).  It was a 3 hour pain in my ass, facilitated by my earlier work with the IMessageFilter and ApplicationEx classes, and it shouldn't have required this much effort, but hey, that's what makes our jobs interesting.

So here's the scoop.  First you need an IMessageFilter implementation.  This can be expanded to the other mouse events, I've only added the MouseDown cause that's all I care about right now.  Feel free to add your own (submit it back if you do, please):

using System;
using System.Windows.Forms;
using System.Collections;

namespace OpenNETCF.Windows.Forms
{
 public delegate void MouseEvent(MouseEventArgs e);

 /// <summary>
 /// Summary description for MouseEventFilter.
 /// </summary>
 public class MouseEventFilter : OpenNETCF.Windows.Forms.IMessageFilter
 {
  private const int WM_MOUSEFIRST                   = 0x0200;
  private const int WM_MOUSEMOVE                    = 0x0200;
  private const int WM_LBUTTONDOWN                  = 0x0201;
  private const int WM_LBUTTONUP                    = 0x0202;
  private const int WM_LBUTTONDBLCLK                = 0x0203;
  private const int WM_RBUTTONDOWN                  = 0x0204;
  private const int WM_RBUTTONUP                    = 0x0205;
  private const int WM_RBUTTONDBLCLK                = 0x0206;
  private const int WM_MBUTTONDOWN                  = 0x0207;
  private const int WM_MBUTTONUP                    = 0x0208;
  private const int WM_MBUTTONDBLCLK                = 0x0209;
  private const int WM_MOUSELAST                    = 0x0209;
  private const int MK_LBUTTON        = 0x0001;
  private const int MK_RBUTTON        = 0x0002;
  private const int MK_SHIFT         = 0x0004;
  private const int MK_CONTROL        = 0x0008;
  private const int MK_MBUTTON        = 0x0010;

  public event MouseEvent MouseDown;
  public event MouseEvent MouseUp;
  public event MouseEvent MouseMove;

  private MouseButtons btns = 0;
  private short x = 0;
  private short y = 0;
  private byte[] pos;

  private bool m_enabled = true;
  private ArrayList m_hwnds;

  public MouseEventFilter()
  {
   m_hwnds = new ArrayList(1);
  }

  public bool Enabled
  {
   get { return m_enabled; }
   set { m_enabled = value; }
  }

  public ArrayList FilterHandles
  {
   get { return m_hwnds; }
   set { m_hwnds = value; }
  }

  #region IMessageFilter Members

  public bool PreFilterMessage(ref Microsoft.WindowsCE.Forms.Message m)
  {
   if(m_enabled)
   {
    // filter if the filter list is empty (filter all hWnds) or if it's marked for filtering
    if((m_hwnds.Count == 0) || (m_hwnds.Contains(m.HWnd)))
    {
     switch(m.Msg)
     {
      case WM_LBUTTONDOWN:
       if(MouseDown != null)
       {
        btns = MouseButtons.None;

        btns |= ((m.WParam.ToInt32() & MK_LBUTTON) > 0) ? MouseButtons.Left : 0;
        btns |= ((m.WParam.ToInt32() & MK_RBUTTON) > 0) ? MouseButtons.Right : 0;
  
        pos = BitConverter.GetBytes(m.LParam.ToInt32());

        x = BitConverter.ToInt16(pos, 0); // LOWORD
        y = BitConverter.ToInt16(pos, 2); // HIWORD

        foreach(MouseEvent me in MouseDown.GetInvocationList())
        {

         me(new MouseEventArgs(btns, 0, x, y, 0));
        }
       }
       break;
     }
    }
   }
   return false;
  }

  #endregion
 }
}

Next you use ApplicationEx to add it to your app, something like this:

static void Main()
{
 eventFilter = new MouseEventFilter();
 myForm = new MyForm();
 ApplicationEx.AddMessageFilter(eventFilter);
 ApplicationEx.Run(myForm);
}

Then in your Form with the ListView, you add your hWnd to the Filter (for better perf):

lvwMyList.Focus();
hwndList = GetFocus();  // use P/Invoke
eventFilter.FilterHandles.Add(hwndList);

And then add a mousedown handler:

eventFilter.MouseDown += new MouseEvent(eventFilter_MouseDown);

Add implementation:

private void eventFilter_MouseDown(MouseEventArgs e)
{
 // determine which item index was clicked
 int topindex = SendMessageInt(hwndList, LVM_GETTOPINDEX, 0, 0);
 int index = topindex + (e.Y / itemheight);

 if(e.X <= 17)
 {
  // on a check
  lstReports.Items[index].ImageIndex = (lstReports.Items[index].ImageIndex == AppGlobal.ICON_CHECKED) ? AppGlobal.ICON_UNCHECKED : AppGlobal.ICON_CHECKED;
 }
 else
 {
  // navigate
  MessageBox.Show("Navigate");
 }
}

And voila - fucking magic.  IMHO, this is a good example of why you pay consultants consultant rates.  How long would it have taken someone with less experience to come up with that?  Today it's a freebie.

Monday, October 18, 2004 10:44:10 PM (Central Daylight Time, UTC-05:00)  #     | 

First, let me point out that I'm not a UI person.  I don't like doing them becasue they don't interest me, and I usually find it to be mostly grunt work, nothing interesting.  Because I don't do UI, I'm only vaguely aware of UI component shortcomings in the CF.  Sure I know several from newsgroup reports, but I've not been really bitten by one - until this weekend that is.

I'm working on a project that has a seeminly simple UI requirement - a two column list of items.  In column 1 is a checkbox, and column 2 is text, preferrably a LinkLabel.  The user can “check” multiple items to remove them from the list with the click of another button, or a click on the text should send them to the detail view of that item.  Simple use of a ListView in detail mode with Checkboxes enabled, right?  I can already see the seasoned CF UI developer smiling....

Take 1: Drop on a ListView, turn on CheckBoxes and FullRowSelect , and run
Interesting.  Every time I tap on a row, the checkbox state toggles.  Who's bright idea was that?  I recall the behavior from the newsgroups, so I Google for a workaround.  Nothing proposed to actually fix it, just ideas for different presentation.  I'm not giving up that easily, I want it to work the way it should.

Take 2: Screw around with P/Invoking ListView Messages
My first thought is that maybe I can find if the user clicked (keep it to yourself, the problem with this idea isn't discovered until Take 4) on the checkbox itself, so I need to determine where its bounds are.  Tried LVM_GETCOLUMNWIDTH and LVM_GETITEMRECT.  Seems that the checkbox isn't a column itself, and there are no APIs I can come up with to get it.  Ugh - I've now burned an hour on something that should be simple, and of course now I can't just let it be.

Take 3: Use my own icon
While playing with the APIs I saw that LVM_GETITEMRECT can get the position of the icon, so in theory I could get the tap position, then use that to find out if it's on the icon, and swap the icon.  I created my icons, added them to a ImageList, removed the Checkboxes and loaded the list.  All is looking good.  I also noticed that LVM_HITTEST can tell me if the icon was tapped without a check for bounds, so I'll implement that once I get thetap location.

Take 4: Added MouseDown and MouseUp handlers
Of course Studio says they're available, but I get nothing.  Maybe it's becasue I'm using the RTM CF.  SP2 fixed a lot, so I'll add that.  While I'm att it I'll add handling in the app to ensure that SP2 is applied in order to run the app.

Take 5: Added the SP2 handler first, then found out that SP2 still didn't add the events.  Crap.  Who made the decisions on what would be supported with this control and did he or she have and clue about how this f'ing control was used in the real world?

So at midnight on Sunday I packed it in.  Next step: unless someone recommends or provides a much simpler solution, I'm going to add an IMessageFilter implementation (fortunately I added that for OpenNETCF or I'd really be screwed), use that to get my mouse location, then use that location with the LVM_HITTEST to see if the icon was tapped, and if it was toggle its state, otherwise navigate.  With all this work I should have just done an implementation of the OwnerDrawnList.  To think I didn't do that because I wanted something simple and easy to implement.

Monday, October 18, 2004 9:03:22 AM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, September 22, 2004

Well I'll be damned, I wrote a new version that uses less memory (about half as much!) and it actually is faster - over 10% faster in fact.  Evidently the loop itself is the time consumer:

public unsafe static string StrRevPtr(string s)
{
  int len = s.Length;

  char[] srcchars = s.ToCharArray();
  char b;

  fixed(char *src = srcchars)
  {
    for(int i = 0 ; i < len / 2 ; i++)
    {
      b = src[i];
      src[i] = src[len-i-1];
      src[len-i-1] = b;
    }
  }

  return new string(srcchars);
}

Wednesday, September 22, 2004 1:04:31 PM (Central Daylight Time, UTC-05:00)  #     | 

Today someone asked about reversing strings in the CF newsgroup.  He had found a snippet on the web that looked like this:

public static string StrRev(string s)
{
   if (s.Length == 1)
     return s;
   else
    
return StrRev( s.Substring(1) ) + s.Substring(0,1);
}

Frightening recursion coupled with slow string access means really bad perf in something like this.  So it was suggested that he remove the recursion and try something like using StringBuilder.Append or Array.Reverse:

public static string StrRevArray( string s )
{
 char[] charArray;
  
 charArray = s.ToCharArray();
 Array.Reverse( charArray, 0, s.Length );
  
 return ( new string( charArray ) );
}

To me, this is missing the forest for the trees.  Why not be efficient and use pointers?  So I wrote a quick test, benchmarked it against the Array.Reverse version and normalized my results against the other posted results. Here's my implementation:

public unsafe static string StrRevPtr(string s)
{
 int len = s.Length;

 char[] srcchars = s.ToCharArray();
 char[] destchars = new char[len];

 fixed(char *src = srcchars, dest = destchars)
 {
   for(int i = 0 ; i < len ; i++)
   {
     dest[len-i-1] = src[i];
   }
 }
 
 return new string(destchars);
}

And the normalized results (using the Compact Framework of course):

Array.Reverse: 114 seconds
StringBuilder.Append: 25 seconds
Indexer in StringBuilder: 20 seconds
Using pointers: 9 seconds

A case of not seeing the forest for the trees perhaps?  Just because it says “unsafe“ doesn't mean “don't use“.  If you're a VB developer, sorry, you'll have to live with poor perf here.

Of course you could save memory by just using a single char buffer and swapping the source array contents - it would be slower than what I propose above, but far more memory efficient.

Wednesday, September 22, 2004 12:46:51 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, August 24, 2004

So today I gave Scott Holden of Compact Framework Dev Team fame to discuss my obsession with the GC.  These were my take-aways from the call:

  1. The GC actually runs *on* the executing thread, so there's no specific GC thread to get ahold of.  So much for that idea (at least I got a real Process Viewer out of it, not that piece of crap Running Programs thing).
  2. Since GC won't happen during a P/Invoke call I was considering calling an unmanaged DLL that would host the EE, pass it a function pointer (evidently available in CF 2.0 - been too busy to actually investigate), and have the DLL run the ISR.  Evidently when you step across the managed/unmanaged boundary in either direction, the GC is given a chance to run.  There goes that idea.
  3. The GC has no mechanisms for telling it not to run.  The only way to prevent it's running in any piece of code is to not make an allocation (simple for the ISR itself).  You must be guaranteed that no allocation happens in the process.  Since the ISR really must run in its own thread, you'd have to have some sort of locking mechanism against *all* memory allocations during the ISR execution.  Ugly if possible at all.  There goes that idea.
  4. Scott believes that “impossible“ is rare in software, though this one borders on very, very difficult.  He said getting a driver hosted in device.exe might be more difficult, but the two are probably the closest to the impossible line he can think of.

So the call left me a bit disappointed.

Since nothing fun ever comes easy, I back-burnered the idea for a while - until I was washing dishes tonight to be precise - and then I had an epiphany - “what alcoholics refer to as a moment of clarity” if you will.

Given that the GC runs on the current thread and given that if you make no allocations during the execution of a section of code (your ISR) then the GC won't run, then all we have to do is to make sure that our ISR makes no allocations and is guaranteed to be the running thread, right?  Well why not use CeSetThreadPriority to set our ISR/IST thread priority higher (well lower numerically) than any other managed thread can go? 

Think of it this way: you have your main thread at priority 251, it creates an IST and sets it's priority to 245 or so.  The IST allocates whatever it needs for the ISR execution and then blocks on a WaitForSingleObject waiting for the interrupt event.  The main thread then runs along merrily until blam!  We get an interrupt.  The IST unblocks and interrupts the primary thread because of its priority (setting a high quantum may be a good idea too?).  The ISR runs, does its thing, then blocks again at WaitForSingleObject.

In theory it sounds good, but right now it's just an idea.  I'll attempt to find time to give it a try in the next few days.  The only problem I see right now is what if the GC is already collecting at the time of the interrupt?  Will the IST be blocked until the GC is done, or will the GC be running on the primary thread, so it in turn will be interrupted by the higher priority IST?  Only experimentation will tell.

Tuesday, August 24, 2004 8:58:38 PM (Central Daylight Time, UTC-05:00)  #     | 
# Saturday, August 21, 2004

Here's a great look from Steven at how POOM will be accessed (most likely anyway) through version 2.0 of the CF.

Saturday, August 21, 2004 8:41:05 PM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, August 20, 2004

So I've been playing with the idea of how you could get deterministic behaviour out of managed code.  Of course the party line is that it's not possible, but to me that's just throwing down the gauntlet.  They also say you can't suspend and resume a managed thread, to which I replied “Yeah? Watch me!”

This was fueled when I was at DevCon and sat in on a lab of Nat Frampton's where you simply create an ISR that responds to a contact on a serial port pin.  I wondered “well why the hell can't I do that in managed code?”  No reason really - I mean it's simply setting up an event to fire when an interrupt is received, and all of that can be P/Invoked (I haven't actually written the code yet, but there's nothing magic about it).  The problem comes with determinism.

Conventional wisdom says that the GC suspends all managed threads when it's doing its work (which can be annoying in most cases).  If this were to happen while you were doing your ISR work, you could get a really bad outlier.  So your system responds in milliseconds most of the time, but occasionally it takes a few seconds.  That's unacceptable - a box flies of the conveyor and hits the floor, making a mess.

So how do we handle this?  How about setting the GC thread priority to 255 at the start of your ISR, then back to it's original priority afterward?  To even better handle it, your ISR priority needs to be set high.

How do we proceed then?  We need the GC thread handle to manipulate its priority.  In comes the toolhelp libraries.  I wrote a ToolHelp wrapper for the SDF earlier in this quest, but I just realized yesterday I only had the PROCESSENTRY32 stuff done, not the THREADENTRY32, so I spent last night doing that piece.

Still, the THREADENTRY32 only has a ThreadID - how are we to determine which thread is the GC as opposed to all the other threads we may have in our process?  Well, I ran a quick check with a slap-together process viewer app based on my new toolhelp wrappers and I see this:

Notice the Priority 248 thread then think about managed priorities - there are five ranging from Lowest (0) to Highest(4), which presumably equate to 255 to 251, though I've yet to check.

My initial thought was that the 248 priority might be the GC, after all it would make sense that it's higher priority, though I also recall that all manged apps need 3 threads.  So why do I have 5?  Well the answer is that this was running through the debugger.  When run stand-alone, I get 3 threads, all with a priority of 251.

So where does that leave us?  Well first, it's evident that 251 is “Normal” priority, so I'll need to map out the actual values for the managed equivalents, but more importantly we still have no way to uniquely identify the GC thread (that I've found anyway).

Right now that's the show stopper.  If you've got any ideas on how to reliably identify the GC thread handle, I'd love to hear them. 

I guess on the plus side, outside of the designer work, it's only about 10 lines of code to create the process viewer you see here.  I'll probably add a few features and turn it into a sample for using the SDF.

Friday, August 20, 2004 12:49:41 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, August 10, 2004

Man, I've been asking for it for sometime and finally here it is, a full explanation of how the GC works in the CF!  Yet more required reading for the CF developer.

Tuesday, August 10, 2004 9:18:58 PM (Central Daylight Time, UTC-05:00)  #     | 
# Monday, July 19, 2004

Well it seems that the response so far has been overwhelming for the competition.  We've had some great additional software license donations (thanks to GUI Innvotions, In The Hand, IDSS and IntelliProg) and and even $300 cash so we'll be opening up some new categories.  I need two things:

1. What categories would you like to see?
2. What cool stuff should we buy with the $300?

 

Monday, July 19, 2004 2:49:31 PM (Central Daylight Time, UTC-05:00)  #     | 
# Saturday, July 17, 2004

Peter Foot has donated 4 copies of the InTheHand Pocket Outlook library and Alex Yakhnin has donated a couple Intelliprog RAS component licenses as well.

If this keeps up we'll have to add another category or two to the .NET Compact Framework Coding Competition.  Any suggestions?

Saturday, July 17, 2004 3:17:47 PM (Central Daylight Time, UTC-05:00)  #     | 
# Tuesday, July 13, 2004

Wei-Meng Lee just donated 4 copies of his book .NET Compact Framework Pocket Guide for the coding competition.  Thanks Wei-Meng!

Tuesday, July 13, 2004 2:48:39 PM (Central Daylight Time, UTC-05:00)  #     | 

Since you're reading my blog, I'll give you some “insider information.”  OpenNETCF Consulting is going to be sponsoring a coding competition in which you can win some cool swag.  The official announcement will happen tomorrow, but you can get a jump on it today!  We'll also be dropping version 1.2 of the SDF for the competition with lots of new fun features.

Here's the 4-1-1 (the links and all may not be active until tomorrow):

First Annual OpenNETCF Coding Competition

 

OpenNETCF Consulting is pleased to announce that we are sponsoring our First Annual .NET Compact Framework coding competition. 

 

General Information

The competition will run from July 15, 2004 until midnight GMT, August 31, 2004 and everyone is invited to compete.  All entries will be accepted, though OpenNETCF.org board members are not eligible to win.  Submissions must follow the the submission guidelines (detailed later) and be posted into the OpenNETCF Wiki (again, more details later) before midnight GMT of August 31, 2004 to be scored and eligible for any prizes.

 

The general purpose of the submissions is to demonstrate using the .NET Compact Framework and the OpenNETCF Smart Device Framework.  To help make the competition objective we have a well-defined score card that all submissions will be scored against, and each submission will be scored by at least three judges.

 

Categories and Prizes

Category:         Smartphone

Prize:                Microsoft Smartphone Developer Kit

Sponsor:           OpenNETCF Consulting

 

Entries in the Smartphone Category simply need to run on the Smartphone 2003 platform.  Beyond that it’s up to your imagination.

 

Category:         Security

Prize:                Security First Ethenticator MS 3000 PCMCIA Fingerprint Reader

Sponsor:           Technobrains.com

 

Since we have a fingerprint reader, we figured a Security Category would be apropos.  What does “Security” mean?  Maybe encryption, maybe something we’ve not thought of.  We’d like to not steer anyone, so again, let your imagination go wild.

 

Category:         Vanilla CE

Prize:                Visual Studio 2003 Professional

Sponsor:           OpenNETCF Consulting

 

A lot of focus is placed on the pocket PC, but there are lots of non-Pocket PC devices out there and they deserve some recognition.  Other than the fact your app should target the Windows CE platform instead of the Pocket PC or Smartphone, it’s up to you what you do.

 

Category:         Pocket PC

Prize:                Hewlett Packard iPaq 4150 Pocket PC

Sponsor:           OpenNETCF Consulting

 

Since the Pocket PC is the popular mainstay of Compact Framework development, it wouldn’t be right for us to leave it out.  Targeting the Pocket PC platform is the only Category rule here.

 

 

We also have the following prizes that will be given for submissions that don’t win but receive honorable mentions:

-         Very useful SanDisk 8in1 USB 2.0 Card Reader/Writer (qty 2)

-         Newly swiped Microsoft Windows Embedded logo short-sleeve shirt (qty 3)

-         Microsoft Embedded DevCon 2004 T-Shirt (at least it’s unworn!) (qty 1)

-         .NET CF Programming with VB.NET by Paul Yao and David Durant (thanks Paul) (qty 1)

-         Any other cool swag we garner between now and the end of the competition

 

All entrants will also receive an ultra-cool OpenNETCF.org sticker (fancy, eh)!

 

Submission Guidelines

All submissions will be as a new topic in the OpenNETCF Wiki found at wiki.opennetcf.org (there’s a link on the front page to the competiton and these rules).  Basically you need to edit the Competition Submissions page, add your app title (Camel case, use no spaces – play in the Sandbox if you need help) and then post the following items:

 

  1. In the Wiki text for your submission, provide the following (there’s a sample available):

-         The category you’re submitting for (you can only have one category)

-         General description of what the app does

-         The idea or purpose the app means to serve

-         What you think is the best part of the app

-         Any explanations for usage, installation or whatever the judges might need to make your app work.  While we’re all technically competent, try to make it simple because if we can’t figure it out, we simply won’t judge it.

  1. Attach your source code in a single ZIP file.  Do *not* include the bin or obj folders or any compiled executable (viruses are not appreciated! ).

You may make any changes after the original submission up until the deadline.

 

You can submit as many apps as you’d like, but you can only win with one.

 

For fairness to everyone, all submissions must have been written during the competition time frame.  Obviously this is on the honor system, but if you submit something you've been working for a year on, it will be fairly obvious.

 

All submitted code must be the submitter's original work and must not have any other license, copyright or whatever attached to it.  Please read the Fine Print below.

 

Peer Feedback

Feel free to add any comments about other submissions at the bottom of the Wiki text page, but do *not* modify the original author’s text or code.  Modifying another competitor’s submission is a quick route to disqualification and stern looks from all.

 

The Score Card

Here’s how we run a tight ship and keep complaints about favoritism to a minimum.  All submissions will be scored against the scorecard below and the highest score in each category wins.  We’ll have at least three judges score your submission, but we’ll try to get more (if you’d like to be a judge, contact us) if we can.  The judges’ scores are final – there’s no arguing or negotiating allowed.  Bribery of judges is frowned upon unless it’s a large sum of money.  Extortion will definitely get you disqualified.  Now let’s get to it. 

 

You can get a maximum score of 100, broken down into 11 Items:

 

Score Item

Criteria

Max Points

1

Following your Category rule(s) and the Submission Guidelines (everyone should get full score here)

5

2

Following accepted coding standards.  This means being consistent in your style, using good capitalization procedures, minimizing use of globals and all that good stuff.

10

3

Code Readability.  Good code should be readable and easy to grasp by anyone, not just the author.

5

4

Good use of comments.  Yes, this sounds like a school teacher talking, but it really is important

10

5

Use of a variety of OpenNETCF Smart Device Framework classes.  Using a single method kind of defeats the purpose of the competition.

25

6

Simplicity.  Doing something in 10 steps to use more OpenNETCF Classes or to show off when 2 steps would do is counter productive

5

7

Innovation.  Did you do something that’s not something everyone sees daily?

10

8

Extensibility.  Could your application be expanded into a larger app?  With only 6 weeks to work, we’re certain you can’t do everything you’d like to

10

9

Good use of OOP.  Using inheritance when warranted and all that.  Don't go overboard though – see Score Item 6

5

10

Wow factor.  Yes this is subjective, but we all have seen apps that just made us say “Wow!”  That’s what these points are for.

10

11

UI Effectiveness.  The UI on CE devices often requires a completely different approach to the UI than a PC application.  Doing things like adding 10,000 items to a ListBox are a good way to score low here.

5

 

Bonus points:  We’ll give a bonus point for each valid bug you find and fix (in the SDF, not in your submission) during your development up to a maximum of 5 points.

 

Fine Print

No competition would be complete without some fine print.

 

  1. All submissions become the property of OpenNETCF Consulting but will remain as shared source under the same license as the OpenNETCF.org Smart Device Framework.  Visit www.OpenNETCF.org for more details on the license.
  2. OpenNETCF Consulting and OpenNETCF.org are not responsible for any damage, problems, disasters or anything caused by either our code or any submitted code. 
  3. All submissions must be the author’s original work and cannot contain code or material that is already copyrighted, owned or otherwise spoken for by any person, company or entity other than OpenNETCF or the submitting author. 
  4. No submissions that fall under the GPL, LGPL or similar license will be accepted.  We simply cannot afford the risk.
  5. No warranty is offered or implied for anything we do.
  6. All prizes are as-is.  They’re all new (in boxes where applicable) and we’re making a good-faith effort to provide them in working order, but if they don’t work or something like that, we’re not responsible and not bound to provide a replacement.
  7. Unclaimed prizes will be held by OpenNETCF Consulting
  8. Winners will be announced when judging is finished.  We make no promises as to when that will be but we’ll try to be expedient.
  9. Anything we’ve not thought of should always be inferred to go in our favor and any we reserve the right to change any of these rules without notification or explanation.
  10. We reserve the right to disqualify any entry or entrant as well as delete any submissions without notification or explanation.
  11. We reserve the right to add to this fine print without notice
Tuesday, July 13, 2004 11:49:43 AM (Central Daylight Time, UTC-05:00)  #     | 
# Friday, July 09, 2004

Jono's blog entry has the list of fixes and the download details.

Friday, July 09, 2004 10:45:16 AM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, July 08, 2004

Neil covered some great mechanisms for getting 10,000 records into a device database:

<quote>
1. Tie one end of a piece of string to the WiFi antenna, if your device has
one, and tie the other end to a tin can. Enumerate the 10,000 records on
your desktop computer and verablly dictate each record into the tin can.

Performance: slow;
Success rate: zero.
Implementation: easy peasy lemon squeezy.

2. Purchase a flock of carrier pigeons, 10,000 in number. Hand-write each
record onto a piece of paper and attach to the bird. Aim the bird at the
device and release.

Performance: slow:
Success rate: zero.
Implementation: possibly very messy.

3. Move to SQL Server. RDA and Merge Replication are your friends.

Performance: good!
Success rate: >1,000,000,000 pigeons.
Implementation: well documented.

4. Hire 10,000 people and get them to memorize one record each. Get them to
follow the device wherever it goes.

Performance: In theory, should outperform Oracle for record access. In
reality, you're statistically likely to get a few "slow" records
Success rate: Depends on the demographics of your recordset.
Implementation: costly, just like Oracle :)

5. Populate the DataSet on the server and transmit as a DataSet object using
Web Services ().

Performance: suffers from a serialization/deserialization overhead which is
costly with 10,000 records.
Success rate: Jackpot, baby!
Implementation: piece of cake.

6. Re-architect your solution. No one should need 10,000 records on a
device. Don't even think about loading that into a ListView either :)

Performance: the best yet.
Success rate: it's the pot of gold at the end of the rainbow.
Implementation: requires some research and reading of those folded paper
thingies.... (books)
</quote>

Thursday, July 08, 2004 11:56:46 AM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, July 07, 2004

I'm back from the Embedded DevCon and I'm working on a new test project idea (true real-time managed code - more on that later). In doing so, I've added some more to the SDF source.  Using Alex Yakhnin's MSDN Article as a base, I've added a ToolHelp namespace with a ProcessEntry class to the SDF.  You can actually create a real Process Viewer (not the crap “running programs” in the PPC) with essentially 2 lines of code beyond the UI work:

To show the processes in a ListBox:
myListBox.DataSource = OpenNetCF.ToolHelp.ProcessEntry.GetProcesses();

To kill a selected process in the list:
((ProcessEntry)myListBox.SelectedItem).Kill();

Once again, I love managed code!

Wednesday, July 07, 2004 1:26:29 PM (Central Daylight Time, UTC-05:00)  #     | 
# Thursday, June 24, 2004

Ask anyone that knows me and they'll say I'm pretty modest about my programming abilities - almost to a fault (it's making finding a new job or contract work right now a bit difficult), but this paper really excites me.  Basically it's the preliminary results of a set of Serial benchmark tests that include the OpenNETCF implementation, and we're way, way out in front.

Of course I'm not solely responsible for the OpenNETCF.IO.Serial library but I did architect it and put a lions share of the code into place (though Udo has been doing a hell of a lot lately as well).  It turns out that our code has latencies that are orders of magnitude less than a commercially available package.  For example, the OpenNETCF library has a latency of around 1ms running on XP, where the commercial library is over 100ms!  The tests gave similar results on two separate Pocket PCs as well.

We didn't have any input or influence on the tests - in fact I wasn't even aware they were being done, so we did no tweaks or fixes to improve the results, these were straight out of the box.  I'd be interested to see the same tests run on some other libraries, including the upcoming implementation in CF 2.0.  It goes to show you don't always get what you pay for.

As a side note, I've got to give kudos to the Microsoft developer that wrote the Queue class.  When I implemented the FIFO in the Port class, I used a Queue, but was concerned about possible performance problems (just look at the comment I put in the code).  This test pretty much removes any doubt in my mind about it's performance.  I'm positive it's done as a basic linked list, but it's still really heartening to see things work so well.

Thursday, June 24, 2004 10:09:29 PM (Central Daylight Time, UTC-05:00)  #     | 
# Wednesday, April 21, 2004
If you're a Pocket PC developer (sorry, this is PPC specific since it uses GAPI), then Geoff's newest (and last since he's left Microsoft to chase gaming) article is phenomenal.  It's rare to see this kind of content in an article, and I hope that Microsoft continues with such superior content.  I know that it sets the bar for what I'll consider article-worthy.
Wednesday, April 21, 2004 10:51:23 PM (Central Daylight Time, UTC-05:00)  #     |