Send mail to the author(s)

May 17, 2008

SDF Futures: Checking for Win32 methods

I've just added a new helper class to the Smart Device Framework that is designed to determine whether a particular Win32 library exists, and whether it exports a specific entry point. It's worth noting at this point that I will assume we're only dealing with .NET Compact Framework applications.

Before I get into the details of the new API, it is always good to have an understanding of the problem we're attempting to address. At the time of writing this, there exists several hundred variants of Windows Mobile devices, and thousands, if not tens of thousands, of Windows CE devices.

From the Windows Mobile aspect of the industry, the devices could be running anything from Windows Mobile 2003 to Windows Mobile 6.1 (I have no doubt that there are even a few Pocket PC 2002 devices still in use today). With each revision of Windows Mobile, new Win32 APIs and extensions to existing APIs emerge from Microsoft and sometimes OEMs add their own domain-specific APIs (e.g. Symbol, Intermec, HHP, etc.), all of which the average mobile developer is keen use in their latest application.

The Windows CE aspect of this scenario is greatly magnified. Windows CE OEMs not only add their own Win32 libraries, but in a lot of the cases, they choose not to add certain Microsoft libraries. This is made really easy for the OEM through the use of catalog items in Platform Builder.

What about the poor developer who has to write an application that runs on a wide variety of Windows Mobile versions and/or Windows CE devices? How can that developer ensure his code takes advantage of the latest APIs on newer devices and degrade elegantly when run on older devices? It turns out there is a perfect example of this scenario with the Connection Manager API.

With Windows Mobile 5.0, Microsoft introduced a new method to the Connection Manager API. This method is ConnMgrRegisterForStatusChangeNotification and is potentially very useful in a lot of Windows Mobile applications. Since this method was only introduced with Windows Mobile 5.0, if you wrote an application that uses this new Win32 method and then ran it on a Windows Mobile 2003 devices, you better be expecting an exception.

Matters are somewhat complicated more because Windows CE 6.0 started shipping a new DLL, cellcore.dll. Those of you familiar with the Connection Manager API will know that cellcore.dll is where you'll find this particular API. However, the Windows CE 6.0 version of cellcore.dll does not contain the Connection Manager API as this is (currently) a Windows Mobile only API.

Obviously, trying to solve the problem by checking for cellcore.dll is insufficient because the potential target devices have some, all, or none of the Connection Manager APIs, but they all have the DLL. You have to increase the granularity of the check down to the individual method. There is no way of doing this from managed code, but thankfully there are native methods that we can easily P/Invoke from the managed world.

Our challenge with the Smart Device Framework is to make this as simple and intuitive as we can so that you don't need to know the exact native methods to call. Below is the class design for the public interfaces in the API.

Using it is pretty simple. To determine if a Win32 library exists on your device:

If Device.Win32Library("cellcore").Exists Then
    ' cellcore.dll exists so you can safely make your P/Invoke calls here
End If

To determine if a specific method exists:

If Device.Win32Library("cellcore").HasMethod("ConnMgrRegisterForStatusChangeNotification") Then
    ' You are safe to make the P/Invoke call to ConnMgrRegisterForStatusChangeNotification
End If

The HasMethod call will simply return False if the Win32 library being referenced does not exist. The only time the API will raise an exception is if you try to trick it with an invalid library extension. For example, the following code will result in an ArgumentException being raised:

Dim libExists As Boolean = Device.Win32Library("somerandomapp.exe").Exists

It's probably worth noting that Device.Win32Library(...) will always return non-null, even if the Win32 library doesn't exist. If you have any feedback on the design, please leave a comment.