Wireless Programming on Windows Mobile: supported or not supported?

  • I can’t take WZC for granted… but, at least, can I programmatically turn WiFi on and off?
  • ossvcs.dll’s Wireless Device Power Management Functions
  • WiFi driver is a Power Manager-controllable NDIS Miniport Driver
  • Introducing: RIL Driver and IP Helper APIs on WM6

As I mentioned in one of my first posts, WiFi Programming is something that depends so much on the WLAN driver developed by the OEM, that an ISV can’t take for granted some interfaces and develop a WiFi-based application that is device-independent. But if a WLAN driver implements the WZC interfaces, then an ISV developer may technically use WZC APIs, even if this is not supported by Microsoft as it is something OEM-dependent. For example, if you want to do so with managed code, then you must read the MSDN article I had already mentioned Building a Wi-Fi Discovery Application with the .NET Compact Framework 2.0 that Chris Tacke wrote some years ago. Also, make sure not to forget that many settings can be done through the Wi-Fi Configuration Service Provider, *IF* the OEM’s WiFi stack properly integrates with the standard WiFi architecture (i.e. it’s WZC-compatible). Note: I’m saying so because I recently worked on a case where querying the Wi-Fi CSP didn’t return anything even if the driver was loaded and even if there was an open connection, and in this case the relevant OEM had to provide the developer with a specific solution.

The issue is the following… ok, ISVs are not supported by Microsoft on controlling the WiFi connection by using WZC APIs because Microsoft can’t know what the OEM did with its WLAN driver: but… can at least ISVs use whatever API to even simply do very basic stuff such as programmatically turn it off and on? Does this simple task really depend on how the OEM developed the driver?

Looking for a solution over the web, you’d find 2 possible approaches, which seem to be OEM-independent:

  1. Use some undocumented APIs exposed by a DLL that is inside every \Windows folder of a WM device (this would also allow to interact with the other wireless radios of the device)
  2. Use Power Manager APIs with the WiFi driver, which is a NDIS Miniport driver controllable by Power Manager (valid for WiFi only)

{SIDE NOTE. Interestingly… while looking for those, I came across the following post: “ The most useful iPhone app I can't release ”. I honestly don’t know the Apple iPhone SDK, therefore can’t express myself on it and didn’t know that it “specifically prohibits using private framework API” (assuming that’s true, based on all the comments of that post): it’s simply interesting to know that WiFi Programmers have similar “non-technical” problems with iPhone platform as well. And I’m sure that Android ones benefit from the “oversights” of the other platforms! That’s the beauty of the competition in a market… (side-by-side note: remember that on Windows Mobile you can programmatically control Bluetooth through the Bluetooth CSP ). }

Let’s go back to Windows Mobile and examine the 2 approaches above.

 

1. Use some undocumented APIs exposed by a DLL that is inside every \Windows folder of a WM device (this would also allow to interact with the other wireless radios of the device)

This is an incredibly powerful approach, because it gives you the power of controlling the power state of all the wireless “devices”: Bluetooth, WiFi and Radio (i.e. the RIL = “Radio Interface Layer”: it’s the driver responsible for radio data connection (GPRS\EDGE\UMTS\..)). And it’s quite well known in the Mobile Community, we all know that \Windows\ossvcs.dll exposes some APIs (GetWirelessDevices, ChangeRadioState, etc, namely the “Wireless Device Power Management Functions”) that allow to develop your own Comm Manager (or Wireless Manager). And using those functions from within a managed application is even easier than on native applications, where you have to dynamically load the library and get the address of the function exposed with a particular ordinal: with managed apps, you can simply use the EntryPoint element of the DllImportAttribute.

Now, let’s pose the usual question: IS THIS SUPPORTED BY MICROSOFT TECHNICAL SUPPORT? The answer is simple here… Is it documented in the SDK? No: ergo it’s not officially supported… Or not? Those APIs are there: if the Dev Team didn’t want ISVs to use them then it wouldn’t develop a DLL which exposes them. Since the solution is well known in the Community and proved to work correctly in most cases, my personal opinion is that the problem is with the documentation here, which is simply missing for those APIs. I’ve asked the Product Group to consider adding the documentation in the public WM SDK… let’s see what that’ll sort out.

Just to be clear, even if one day those Wireless Device Power Management APIs will be fully documented and ready to be used by ISVs, what more can Microsoft Technical Support do after verifying that an ISV used the functions correctly? If those Wireless Device Power Management Functions don’t work correctly with one of the wireless drivers, chances are that the problem is with the driver, not with the functions (considering that the same APIs work correctly in other cases). And who develops the driver and technically has the ability to give support about it? Only the OEM…

 

2. Use Power Manager APIs with NDIS Miniport driver (valid for WiFi only)

If you look at pm.h header file of the WM5\6 SDKs, you’ll find a constant, which is is even public for 5.0 here and for 6.x here:

 #define PMCLASS_NDIS_MINIPORT           TEXT("{98C5250D-C29A-4985-AE5F-AFE5367E5006}")

If you examine the registry contents at [HKLM\System\CurrentControlSet\Control\Power\State], you’ll see “devices” whose power-state can be controlled thru Power Manager APIs, accordingly to the SDK Documentation. One of those devices is the WiFi driver, described as “ {98C5250D-C29A-4985-AE5F-AFE5367E5006}\<device name chosen by the OEM> ” (The name can be seen also for example in the IPConfig section of the log generated by the Windows Mobile Network Analyzer PowerToy). Since the device appears under that registry key, an ISV can programmatically control its power state by using the documented Power Manager API SetDevicePower():

 [DllImport("coredll.dll", SetLastError = true)] 
private static extern int SetDevicePower(string pvDevice, int dwDeviceFlags, DevicePowerState DeviceState); 

private enum DevicePowerState : int 
{ 
    Unspecified = -1, 
    D0 = 0, // Full On: full power, full functionality 
    D1, // Low Power On: fully functional at low power/performance 
    D2, // Standby: partially powered with automatic wake 
    D3, // Sleep: partially powered with device initiated wake 
    D4, // Off: unpowered 
}

private const int POWER_NAME = 0x00000001;

So, to turn the WiFi ON:

 string driver = Utilities.WiFi.FindDriverKey(); 
SetDevicePower(driver, POWER_NAME, DevicePowerState.D0);

And OFF:

 string driver = Utilities.WiFi.FindDriverKey(); 
SetDevicePower(driver, POWER_NAME, DevicePowerState.D4);

Utilities.WiFi.FindDriverKey() is simply a function that returns the whole registry key name of the key containing the NDIS MINIPORT class GUID defined in the SDK’s pm.h:

 private static string FindDriverKey() 
{ 
     string ret = string.Empty; 

     //#define PMCLASS_NDIS_MINIPORT           TEXT("{98C5250D-C29A-4985-AE5F-AFE5367E5006}") 
     //(From "c:\Program Files (x86)\Windows Mobile 6 SDK\PocketPC\Include\Armv4i\pm.h") 
     string WiFiDriverClass= "{98C5250D-C29A-4985-AE5F-AFE5367E5006}";  

     foreach (string tmp in Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Power\\State", false).GetValueNames()) 
     { 
         if (tmp.Contains(WiFiDriverClass)) 
         { 
             ret = tmp; 
             break; 
         } 
     } 

     return ret; 
}

This proved to work on some devices I’ve tested it with, after reboots and also consistently with the Wireless Manager\Comm Manager of the device. I’ve found a forum post stating that on iPAQ devices this approach doesn’t work (and this is in line with the fact that HP provided a DLL within its private SDK exposing specific APIs to interact with their driver), however I tested this approach on an iPAQ Smartphone and it worked as well.

Now, the usual question: IS THIS SUPPORTED OR NOT BY MICROSOFT TECHNICAL SUPPORT? Every single detail an ISV uses in this approach is documented, hence supported. Cool! But… again, as before… what more can Microsoft Technical Support do after verifying that the ISV used the functions above correctly? If a Power Manager API doesn’t work correctly with a driver, chances are that the problem is with the driver, not with the PM API (considering that the same API works correctly in other cases). And who develops the driver and has technically the ability to give support about it? Again, the OEM…

 

I hope things are a bit clearer now… just let me know in case that’s not true!

 

Cheers,

~raffaele

 

P.S.: There’s an interesting point about NDIS Miniport drivers. On WM5, Microsoft's recommendation to OEMs was to implement the RIL Driver as PPP Adapter. Among other things, that allowed developers using IP Helper APIs to easily retrieve the related adapter information because the string "[Cellular Line]" was contained in the Adapter's name, for example thru the GetAdaptersInfo() API. Now, starting on WM6 Microsoft encourages OEMs to implement the RIL as NDIS Miniport driver, because this way the device will be ready to support simultaneous data calls (with PPP you can’t do that): "[...] One advantage of using WWAN-based GPRS connections is the ability to establish multiple GPRS connections simultaneously" (Establishing a WWAN-based GPRS Connection).

Note that not every single WM6.x device has already the RIL implemented as NDIS Miniport driver, demonstrating once again how OEMs have complete power on this. So, if you use IP Helper APIs or simply look the ipconfig report of the Windows Mobile Network Analyzer PowerToy, on WM6 devices where the OEM hasn’t yet “upgraded” the RIL you’ll still see

  • PPP Adapter [Cellular Line] :

    • Adapter Name ...... : Cellular Line

while on those WM6 devices where the RIL is already implemented as NDIS Miniport driver

  • Ethernet adapter Local Area Connection:

    • Adapter Name ...... : WWAN1-IBOX.TIM.IT-1 (for example)

therefore it's no longer distinguished from for example the WiFi connection:

  • Ethernet adapter Local Area Connection:

    • Adapter Name ...... : TNETW12511 (for example)

At TCP\IP Protocol level (e.g. by using IP Helper API GetAdaptersInfo), on those WM6 devices where the OEM followed Microsoft's recommendations for the RIL there’s no way to distinguish if a connection is WLAN (=WiFi) or WWAN (=RIL). In future I plan to post about another approach, probably based on NDISUIO (“NDIS User-mode I/O”)… I firstly need to be sure I’ll talk about something “SUPPORTED”… (that’s always my #1 priority! Or not? :-)

 

P.P.S.: Happy birthday to this blog!! THANK EVERYONE FOR READING\COMMENTING\CONTACTING ME, I couldn’t absolutely imagine the success it had in our Community (does it really deserve it? :-), so thanks again!! If you have any suggestion on anything, just let me know!