Export (0) Print
Expand All

Building a Wi-Fi Discovery Application with the .NET Compact Framework 2.0

.NET Compact Framework 1.0
 

Chris Tacke
OpenNETCF.org

February 2006

Applies to:
   Microsoft .NET Compact Framework version 1.0
   Microsoft .NET Compact Framework version 2.0
   Windows Mobile–based devices

Summary: Learn how to use the .NET Compact Framework 2.0 and the OpenNETCF shared source library to create an application that detects available wireless networks and retrieves configuration information from a smart device's wireless network adapter. (10 printed pages)


Download Build_WiFi_Discover_App_NETCF2.msi from the Microsoft Download Center.

Contents

Introduction
OpenNETCF.org, Smart Device Framework, and Shared Source License
OpenNETCF.Net Namespace
Under the Hood
Conclusion

Introduction

In today's world of mobile and embedded devices, wireless Ethernet (or Wi-Fi) network adapters are becoming commonplace, and wireless hotspots are nearly ubiquitous in most technology-savvy locations.

Unfortunately, being able to discover available wireless networks on a Windows Mobile–based device with the standard user interface (UI) isn't straightforward, and the Wireless Zero Configuration (WZC) application programming interface (API) set.

WZC is a standardized set of interfaces that Microsoft designed for wireless network cards. If a wireless card's driver is written to interface with WZC, it can be controlled and queried through this standardized interface, making configuration and status querying code consistent—regardless of the manufacturer of the adapter. While not all wireless cards are WZC–compatible, many are, and the high adoption rate is making it a defacto standard on both Windows-based desktop computers and Windows Mobile operating systems. Unfortunately, the WZC interface in Windows CE is completely undocumented.

So what can embedded developers do? This article will show you how to use a robust shared-source (not open-source) library from OpenNETCF.org to write a feature-rich application for displaying network adapter properties and discovering nearby wireless access points. The sample application will have only about 200 lines of hand-typed code—and that length includes comments, white spaces, and brackets.

If you're interested in exactly what is going on behind the scenes, this article has a download code sample for the "OpenNETCF.Net" namespace (though the project works fine if you reference the OpenNETCF.Net.dll assembly). This article also looks at the complexity about what really happens when developers make four simple calls to the library.

OpenNETCF.org, Smart Device Framework, and Shared Source License

Any time you introduce third-party software into your solution, you must analyze the benefits and risks of usage. So before you learn more about the sample application, you should learn about the basics of OpenNETCF.org, the Smart Device Framework, and the OpenNETCF Shared Source License.

First, OpenNETCF.org is a project run by OpenNETCF Consulting, LLP. It was started "in the spirit of the Open Source Movement." The project provides solutions to problems that the .NET Compact Framework development community began running into from the first beta releases.

The primary product of the OpenNETCF.org project is the Smart Device Framework, which is an extensive set of classes that complement the .NET Compact Framework versions 1.0 and 2.0. The Smart Device Framework provides many of the classes, properties, and methods that are available in the full .NET Framework, plus a large complement of classes that are specific to the Windows CE environment.

Essentially, the Smart Device Framework is a framework that enables .NET Compact Framework developers to provide more feature-rich solutions with less time to market than with the .NET Compact Framework alone. Best of all, you get the full source code; it's 100 percent free; and the distribution license is very friendly. The OpenNETCF Shared Source License for the Smart Device Framework versions 1.0 through 1.4 is very developer and business friendly. This article doesn't cover it in detail—only the highlights. However, it's only one page; it's written in very simple language; it has been reviewed by legal teams of multi-billion-dollar companies, and it was found to be acceptable for use. You can review the full license, but it essentially says that:

  • You are free to use and distribute the Smart Device Framework with your application if you agree to add some significant value to the end product.
  • You can use as much or little of the Smart Device Framework as you want.
  • You can distribute the OpenNETCF assemblies as provided or take the source and roll it into your own product.
  • Somewhere in the documentation for your product, you need to state that you used the Smart Device Framework.
  • You can't simply compile and sell the framework as a stand-alone product.
  • You can't hold OpenNETCF responsible for problems due to usage.

The Smart Device Framework has been downloaded nearly 200,000 times, is nearly two years old, and (in complete form) is nearly as large as the .NET Compact Framework 1.0. The Smart Device Framework has been tested to a degree, but it's a community project, so it may have some bugs, and some areas have received more development attention than others.

Now that you understand the few risks, you can look at the huge benefits that the Smart Device Framework provides.

OpenNETCF.Net Namespace

For the sample application in this article, you'll use only a single namespace from the Smart Device Framework: "OpenNETCF.Net." The source code is roughly 3,800 lines, so immediately, you can see that if the code works (you'll see that it does) and if you use most of it (you will), you can potentially save weeks of development.

The namespace contains a large number of classes for network usage, including File Transfer Protocol (FTP), network statistics, and Bluetooth. But this article focuses on four classes: Adapter and AccessPoint, plus AdapterCollection and AccessPointCollection, which are, as their names imply, collection classes of the previous two.

Figure 1 is a simple diagram of the classes.

Click here for larger image

Figure 1. The Adapter, AccessPoint, and associated collection classes. Click the thumbnail for a larger image.

Adapter and AdapterCollection Classes

The Adapter class represents any Ethernet-compatible network adapter in the system. This adapter can be a wired or wireless network card or anything else that presents an Ethernet layer to the network driver interface specification (NDIS), such as an active Microsoft ActiveSync connection over universal serial bus (USB), serial, or Infrared Data Association (IrDA).

As you saw earlier in Figure 1, the Adapter class presents a large number of properties, most of which describe either Internet Protocol (IP) configuration items (like IP address, gateway, and subnet mask) or wireless connection information, such as signal strength.

The example in this article uses the Adapter class to present the commonly used adapter configuration information for any adapter—wireless or not.

The AdapterCollection class is simply a CollectionBase-derived class that provides a container for adapters returned by a call to Networking.GetAdapters.

As shown in the following code example, you first need to get a list of all NDIS adapters that the device has, which comes in the form of an AdapterCollection class returned from Networking.GetAdapters. When the example application starts, you get a list by calling UpdateAdapters, which gets the AdapterCollection class and populates a combo box with the adapter names.

void UpdateAdapters()
{
    // Get the available adapters
    m_adapters = Networking.GetAdapters();

    // Clear the combo
    cboAdapters.Items.Clear();

    // Add the adapters
    foreach (Adapter adapter in m_adapters)
    {
        cboAdapters.Items.Add(adapter);
    }
}

Every time the user changes the selected (or current) adapter, the UI is updated with the selected adapter's configuration information by a call to UpdateConfig, as shown in the following code example.

void UpdateConfig()
{
    tabConfiguration.SuspendLayout();

    // Update the adapter's configuration information
    lblMACAddress.Text = 
        BitConverter.ToString(m_currentAdapter.MacAddress);

    lblIPAddress.Text = m_currentAdapter.CurrentIpAddress;
    lblSubnet.Text = m_currentAdapter.CurrentSubnetMask;
    lblGateway.Text = m_currentAdapter.Gateway;

    // Wireless information
    bool wireless = m_currentAdapter.IsWireless;
    if (wireless)
    {
        lblIsWireless.Text = "True";
        lblWZCCompat.Text = 
            m_currentAdapter.IsWirelessZeroConfigCompatible.
                                                    ToString();
    }
    else
    {
        lblIsWireless.Text = "False";
        lblWZCCompat.Text = "N/A";
    }

    // Dynamic Host Configuration Protocol (DHCP) information
    bool dhcpEnabled = m_currentAdapter.DhcpEnabled;
    if (dhcpEnabled)
    {
        lblDHCPEnabled.Text = "True";
        lblLeaseObtained.Text =
            m_currentAdapter.LeaseObtained.ToShortDateString();
        lblLeaseExpires.Text = 
            m_currentAdapter.LeaseExpires.ToShortDateString(); ;
        mnuRenew.Enabled = true;
    }
    else
    {
        lblDHCPEnabled.Text = "False";
        lblLeaseObtained.Text = "N/A";
        lblLeaseExpires.Text = "N/A";
        mnuRenew.Enabled = false;
    }

    tabConfiguration.ResumeLayout();
}

Figure 2 shows the Configuration tab of the example application running on an HP iPAQ H5555 device. The selected adapter is the built-in 802.11b controller. When the device is connected through ActiveSync over Transmission Control Protocol/Internet Protocol (TCP/IP), the ActiveSync connection will also enumerate as an adapter.

Figure 2. Adapter configuration information for the built-in 802.11b adapter on an HP iPAQ H5555 device

For the Wi-Fi discovery goal of this article, the important property here is IsWirelessZeroConfigCompatible. If a wireless adapter in not WZC compatible, most of its properties are accessed through proprietary API calls, which are often not documented or published, leaving developers without the ability to create custom implementations or software. However, if an adapter is WZC compatible (more and more are), you can use a standard set of Windows APIs to get a large amount of information about the adapter and the network access points that the adapter recognizes.

As mentioned before, the WZC APIs are not formally documented. But Microsoft Platform Builder comes with the source code for the default network UI that connects to WZC–compatible adapters, and that source code provides a way—albeit non-trivial—to see how the APIs work, and these APIs are available in a user-friendly form through the OpenNETCF.Net.AccessPoint class.

AccessPoint and AccessPointCollection Classes

The primary node of interest in a wireless network is the access point. When you're working with access points for a specific adapter, there are two general categories that they fall into: access points that the adapter can recognize now, and access points that the adapter has recognized in the past and that the adapter will give preferential treatment to if it encounters them again. These lists are usually different, but they will often contain some of the same access points. In the AccessPoint class, these access points are defined as nearby (often referred to as available) access points and preferred access points, respectively. The third term for an access point of importance is the associated access point, which is the access point that you're currently running your network traffic through in this example. It's quite possible to have no associated access points—for instance, if you're not in range of any access point, but if you're associated, the associated access point is always in the list of nearby access points.

In this example, you get and display both lists: the preferred access points and the available access points. For those access points that the currently selected adapter recognizes, the signal strength is listed in decibels along with a text description like Excellent, Good, Fair, or Poor.

You can see in Figure 3 that the current example contains two available access points, both of which have excellent strength because they are less than a foot from the access points. The AccessPoint class also has a few other properties to provide information about its capabilities and privacy.

Figure 3. Available (nearby) wireless networks

Under the Hood

While the code used to make the WiFiDiscovery application is quite simple, it belies how much work is actually going on above the layer of the .NET Compact Framework in the OpenNETCF library. The call to Networking.GetAdapters uses platform invoke to call the iphlpapi.dll file's GetAdaptersInfo function, which returns an array of native structures—one for each network adapter (wireless or otherwise) that is registered with the system.

These structures are marshaled from the native API as IP_ADAPTER_INFO classes internally, which is how the API returns the data. Each IP_ADAPTER_INFO class is translated to the exposed managed Adapter class to provide the general information that all adapters expose—like the adapter's name, MAC address, and IP configuration.

If the adapter is reported as an Ethernet adapter, the adapter is then queried to see if it wireless and if it supports the WZC interface by using platform invoke to call the wzcsapi.dll file's WZCQueryInterface API.

If an adapter is found to be wireless, a fair amount of information can be queried about it through the device's NDIS driver, again by using platform.

If an adapter is also found to be WZC–compatible, you can derive even more information by using platform invoke to call the WZCQueryInterface API with different parameters. For example, you can query the array of available or associated access points.

If you query for nearby access points, it's even more complex because platform invoke calls to the NDIS driver.

As a brief example of what happens with just a few simple calls, look at the flow of data in the system when you want to find the nearby access points for the first adapter in the system. In WiFiDiscovery.exe, the code would look like these four simple lines:

AdapterCollection adapters = Networking.GetAdapters();
adapters[0].IsWireless;
adapters[0].IsWirelessZeroConfigCompatible;
AccessPointCollection aps = adapters[0].NearbyAccessPoints;

What actually happens in the system is shown in Figure 4.

Click here for larger image

Figure 4. Data flow for getting the list of available (nearby) wireless networks for an adapter. Click the thumbnail for a larger image.

Conclusion

The purpose of the .NET Compact Framework and managed code in general is to increase developer productivity. High productivity means faster time to market and richer feature sets. It means lower-cost solutions, lower opportunity costs, and more resource availability for other projects.

Although the example application covered in this article isn't as robust as a complete wireless application can be—for example, it doesn't have icons for the access point infrastructure or the ability to change access point associations—it does prove the point of productivity. By using a free shared-source library, you've created a basic Wi-Fi discovery application with less than 200 lines of typing. The application shows all of the adapters available. For wireless adapters, the application shows all of the available and preferred access points, along with their signal strengths. As a bonus, this article includes the seven lines of code to renew any adapter's DHCP address (and it would have been only one line if the intended result was a more basic UI).

Managed code isn't the solution to every business problem, and C/C++ definitely has its place, but in today's fast-paced business climate, developers must always work to provide customers more for less. Managed code, coupled with the Rapid Application Development tools available with Microsoft Visual Studio 2005, provides a solid base for developers to successfully compete in the marketplace.

Show:
© 2014 Microsoft