A service for Scanning and Connecting to WiFi Networks from the CF

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();
}
}
}
}

New ORM Release

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). 

Loading parts of large images in the Compact Framework

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 240×480.  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 2048×1536 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:

Getting Native File Info in the Compact Framework

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(”);
p += keyLength;
var value = Marshal.PtrToStringUni(new IntPtr(p), valueChars).TrimEnd(”);
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:


 

Setting a Custom Cursor in a Compact Framework application

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.

OpenNETCF.ORM update

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.