Establishing Network Connectivity with the Windows Mobile Connection Manager

4/7/2010

Jim Wilson, JW Hedgehog, Inc.

August 2007

Summary

This article focuses specifically on demonstrating how you can use the Microsoft® Connection Manager to establish a network connection and release a connection from a managed application. The focus of this article is the concepts behind establishing connections and disconnecting connections with the Connection Manager, not a specific managed wrapper over the Connection Manager API. The goal of this article is to cover the concepts in such a way that they can be applied to any Connection Manager managed API.

Applies To

Windows Mobile 6 Professional

Windows Mobile 6 Standard

Windows Mobile 6 Classic

Windows Mobile 5.0 for Pocket PC Phone Edition

Windows Mobile 5.0 for Smartphone

Windows Mobile 5.0 for Pocket PC

Introduction

Accessing Connection Manager from Managed Code

Establishing a Connection

Conclusion

Introduction

Modern Windows Mobile devices include a number of network connectivity options such as Wi-Fi and various cellular radios. In addition, all Windows Mobile devices can access the network through your desktop computer when the device is connected to the desktop computer through Microsoft ActiveSync®, a feature known as pass-through networking.

Each of these network options provide significantly different data speeds and at any given time zero, one, or more of the network connections may be available. When an application needs to establish a network connection, rather than requiring the application to go through the work of determining which connections are available and then selecting the most appropriate connection, Windows Mobile provides a common solution to this task in the form of the Connection Manager.

As the name suggests, the Connection Manager is responsible for managing all of the network connections on a device. When an application needs to establish a network connection, the application simply tells the Connection Manager what kind of connection is required, such as the Internet, and the Connection Manager identifies which connections are available, selects the most optimal connection, and then establishes that connection as necessary; the Connection Manager may even share a connection between multiple applications with the same connection requirements. The application is completely abstracted from these details and is able to use the connection without concern for the details.

The Connection Manager is very powerful and provides a number of different connection-related capabilities. This article focuses specifically on demonstrating how you can use the Connection Manager to establish a network connection and release a connection when you no longer need it.

Although the examples in this article p/invoke directly to the Connection Manager native API, the focus of this article is the concepts behind establishing connections and disconnecting connections with the Connection Manager, not a specific managed wrapper over the Connection Manager API. The goal of this article is to cover the concepts in such a way that they can be applied to any Connection Manager managed API.

Accessing Connection Manager from Managed Code

Connection Manager is a fundamental part of Windows Mobile but it currently exposes only a native API. The good news is that most of these APIs are simple and can be easily accessed from the .NET Compact Framework. There are a few enumerations and structures that you will also need to define but for the most part, the process is relatively simple.

Note

.NET Compact Framework 3.5, included with Microsoft Visual Studio® 2008, provides a managed implementation of the Connection Manager API. Even if you are planning to use the managed version of the API, you are still encouraged to read this article as the concepts discussed remain the same whether using a managed API or p/invoking to the native methods.

Connection Manager Functions

The Connection Manager API consists of about 11 functions, but you only need five of these functions for the tasks of establishing and releasing a network connection. In many cases, your application may require as few as two of these functions. Table 1 shows these five functions.

Table 1. Connection Manager functions used to establish and release a network connection

Function Description

ConnMgrMapURL

Retrieves the network identifier (Internet or Work) for the specified URL.

ConnMgrEstablishConnection

Selects and establishes the appropriate connection for the specified network identifier. This method returns without waiting for the connection attempt to complete; use ConnMgrConnectionStatus to determine the connection status.

ConnMgrEstablishConnectionSync

Selects and establishes the appropriate connection for the specified network identifier. This method does not return until the connection attempt completes.

ConnMgrReleaseConnection

Releases the specified connection, which may also close the connection.

ConnMgrConnectionStatus

Retrieves the status of the specified connection.

To access these five functions from your .NET Compact Framework application, you will need to include the p/invoke declarations shown in the following code.

[DllImport("CellCore.dll")]
static extern int ConnMgrMapURL(string url, ref Guid networkGuid, int passZero);
[DllImport("CellCore.dll")]
static extern int ConnMgrEstablishConnection(ConnMgrConnectionInfo connectionInfo, ref IntPtr connectionHandle);
[DllImport("CellCore.dll")]
static extern int ConnMgrEstablishConnectionSync(ConnMgrConnectionInfo connectionInfo, ref IntPtr connectionHandle, uint dwTimeout, ref ConnMgrStatus dwStatus);
[DllImport("CellCore.dll")]
static extern int ConnMgrReleaseConnection(IntPtr connectionHandle, int cache);
[DllImport("CellCore.dll")]
static extern int ConnMgrConnectionStatus(IntPtr connectionHandle, ref ConnMgrStatus status);

Connection Manager Enumerations and Structures

When you use the Connection Manager to establish a connection, you must specify the characteristics of the desired connection. In native code you specify these characteristics using a native structure, CONNMGR_CONNECTIONINFO, and several groups of #define macros. To make the structure more consistent with other features of .NET, you might implement the native structure as a managed class and name the managed class something like ConnMgrConnectionInfo. Rather than representing the macros as constants in .NET, you can create more explicit groupings of the macros by defining each group of related macros as a set of enumeration values.

Note

If you would like to check out the various Connection Manager native code declarations, take a look at the connmgr.h C++ header file located in %Program Files%\Windows Mobile 6 SDK\PocketPC\Include\Armv4i.

Several of the structure members rely on the macros, so the first thing to do is define the enumerations that correspond to the macros.

The first enumeration corresponds to the CONNMGR_PARAM_* family of macros. These values identify which of the criteria fields in the structure are valid. The criteria-related fields in the structure specify the desired characteristics of the requested connection. A connection request can specify multiple criteria therefore the enumeration declaration includes the Flags attribute as shown in the following code. By marking the enumeration with the Flags attribute, you can bitwise-or the members together.

[Flags]
enum ConnMgrParam : int
{
    GuidDestNet = 0x1,
    MaxCost = 0x2,
    MinRcvBw = 0x4,
    MaxConnLatency = 0x8
}

Each of the enumeration members have the same name as the structure field to which they correspond. The upcoming discussion of the structure definition will address the meanings of each of the fields.

The next enumeration corresponds to the CONNMGR_FLAG_PROXY_* macros. These values specify the types of proxy servers that Connection Manager can use to establish the connection. Like the ConnMgrParam enumeration, this declaration includes the Flags attribute as shown in the following code.

[Flags]
enum ConnMgrProxy : int
{
    NoProxy = 0x0,
    Http = 0x1,
    Wap = 0x2,
    Socks4 = 0x4,
    Socks5 = 0x8
}

The next thing to consider when requesting a connection is the priority of the request. The Connection Manager is responsible for all connections on the device and tries to service as many of the requests for those connections as possible. To assist the Connection Manager in determining the order and importance of each request, each request must specify its priority. The Connection Manager supports several different priority levels; however, applications commonly use only a few of these values. The following code shows the enumeration declaration with the commonly used priority values.

enum ConnMgrPriority
{
    UserInteractive = 0x8000,
    HighPriorityBackground = 0x0200,
    LowPriorityBackground = 0x0008
}

Table 2 provides a description of each of these priorities.

Table 2. Common Connection priorities

Priority Description

UserInteractive

A user-initiated action has requested the connection and the user interface is waiting for the connection. This priority supersedes most other priorities.

HighPriorityBackground

The connection request is of high priority, but the application is in the background and therefore not affecting the user interface.

LowPriorityBackground

The connection request only connects if another higher priority application is already using the requested path. Using this priority, an application may share an existing connection but will not establish a new one.

Connection Manager supports a number of priority values beyond those in the enumeration declaration. The CONNMGR_PRIORITY_* macros in the connmgr.h header file provide the complete list. For a description of the priority values not listed in Table 2, check out Connection Manager Priority Constants.

The last enumeration is for the connection status values. For the most part, the names of each status value are self-explanatory. For a description of each status value, see Connection Manager Status Constants or look at the CONNMGR_STATUS_* macros in the connmgr.h header file. The following code shows the status value enumeration.

enum ConnMgrStatus
{
    Unknown = 0x00,
    Connected = 0x10,
    Suspended = 0x11,
    Disconnected = 0x20,
    ConnectionFailed = 0x21,
    ConnectionCanceled = 0x22,
    ConnectionDisabled = 0x23,
    NoPathToDestination = 0x24,
    WaitingForPath = 0x25,
    WaitingForPhone = 0x26,
    PhoneOff = 0x27,
    ExclusiveConflict = 0x28,
    NoResources = 0x29,
    ConnectionLinkFailed = 0x2a,
    AuthenticationFailed = 0x2b,
    NoPathWithProperty = 0x2c,
    WaitingConnection = 0x40,
    WaitingForResource = 0x41,
    WaitingForNetwork = 0x42,
    WaitingDisconnection = 0x80,
    WaitingConnectionAbort = 0x81
}

With all of the enumerations defined, the next thing to do is understand the connection request structure. As you are likely aware, you can represent a native structure as either a managed structure or a managed class. In general, classes are a little more flexible than structures because classes allow you to provide a default constructor and use member initializers. As mentioned earlier in this article, the ConnMgrConnectionInfo managed class represents to the CONNMGR_CONNECTIONINFO native structure. The following code shows the ConnMgrConnectionInfo class definition.

[StructLayout(LayoutKind.Sequential)]
class ConnMgrConnectionInfo
{
    Int32 cbSize;                          // DWORD
    public ConnMgrParam dwParams = 0;      // DWORD
    public ConnMgrProxy dwFlags = 0;       // DWORD
    public ConnMgrPriority dwPriority = 0; // DWORD
    public Int32 bExclusive = 0;           // BOOL
    public Int32 bDisabled = 0;            // BOOL
    public Guid guidDestNet = Guid.Empty;  // GUID
    public IntPtr hWnd = IntPtr.Zero;      // HWND
    public UInt32 uMsg = 0;                // UINT
    public Int32 lParam = 0;               // LPARAM
    public UInt32 ulMaxCost = 0;           // ULONG
    public UInt32 ulMinRcvBw = 0;          // ULONG
    public UInt32 ulMaxConnLatency = 0;    // ULONG 
} ;

The description of each of the structure fields is in Table 3.

Table 3. ConnMgrConnectionInfo class members

Field Description

cbSize

The size of the class in bytes.

dwParams

The list of class criteria fields to consider when selecting the connection. To specify multiple criteria fields, use a bitwise-or to combine multiple ConnMgrParam enumeration values.

dwFlags

The connection request's proxy requirements.

dwPriority

The connection request's priority.

bExclusive

The connection request's exclusivity; a non-zero value indicates that connection cannot be shared with other applications.

bDisabled

The connection request's indicator whether the Connection Manager should establish the connection; a non-zero value indicates that the Connection Manager should determine if the connection is possible but not actually perform the connection. When the Connection Manager reaches the point where it would normally establish the connection, the Connection Manager sets the connections status to ConnMgrStatus.ConnectionDisabled.

guidDestNet

The connection request's destination expressed as a GUID; if this field is valid the dwParams field must contain ConnMgrParam.GuidDestNet.

hWnd

The handle of the window to send status change messages; this will normally be the handle of a MessageWindow-derived class.

uMsg

The message to send to the window identified by the hWnd field when sending status change messages; this field is only valid if the hWnd field is set to a valid window handle.

lParam

A value to include in the status change message sent to the window identified by the hWnd field; this field is only valid if the hWnd field is set to a valid window handle. Use this field to include application-specific data in the status change message.

ulMaxCost

The maximum acceptable cost of the connection; if this field is valid the dwParams field must contain ConnMgrParam.MaxCost (most applications can ignore this field).

ulMinRcvBw

The minimum acceptable reception bandwidth of the connection; if this field is valid the dwParams field must contain ConnMgrParam.MinRcvBw (most applications can ignore this field).

ulMaxConnLatency

The maximum acceptable connection latency expressed in milliseconds; if this field is valid the dwParams field must contain ConnMgrParam.MaxConnLatency (most applications can ignore this field).

To simplify working with the ConnMgrConnectionInfo class, the class definition includes a couple of constructors that take care of some common situations. First is the default constructor, which is shown in the following code example.

public ConnMgrConnectionInfo()
{
    cbSize = Marshal.SizeOf(typeof(ConnMgrConnectionInfo))
} 

Before passing the ConnMgrConnectionInfo class to any of the Connection Manager functions, the size of the class must be stored in the cbSize member so this constructor automatically stores the class size in cbSize as part of the class construction.

Although the ConnMgrConnectionInfo class has several members, applications often need to set only the destination, the priority, and if needed, the proxy; to include the destination in the connection request criteria the dwParams member is set to ConnMgrParam.GuidDestNet. The constructor shown in the following code handles this situation.

public ConnMgrConnectionInfo(Guid destination, ConnMgrPriority priority, ConnMgrProxy proxy)
    : this()
{
     guidDestNet = destination;
     dwParams = ConnMgrParam.GuidDestNet;
     dwPriority = priority;
     dwFlags = proxy;
} 

For convenience, the class contains two other constructors that represent common situations. The first accepts the destination and priority, and sets the connection criteria to indicate that no proxy is necessary. The second accepts the destination and sets the connection request priority to ConnMgrPriority.UserInteractive, which is the priority of a connection for which the application user interface is waiting.

public ConnMgrConnectionInfo(Guid destination, ConnMgrPriority priority)
    : this(destination, priority, ConnMgrProxy.NoProxy) { }

public ConnMgrConnectionInfo(Guid destination)
    : this(destination, ConnMgrPriority.UserInteractive) { }

Establishing a Connection

With the native method entry points, enumerations, and structure all defined, you are now ready to use the Connection Manager to establish a connection. The good news is that the hard work is done; using the Connection Manager is quite easy. Establishing the actual connection involves two steps: determining the network destination identifier and making the connection request.

Determining a Network Destination Identifier

The first step to establishing a connection is to identify whether your application needs to connect to the Internet or your Work network. Each network destination has a specific GUID. The GUID for the Internet is 436EF144-B4FB-4863-A041-8F905A62C572. The GUID for your Work network is A1182988-0D73-439e-87AD-2A5B369F808B.

Although the GUIDs for each of the network destinations are well known, most applications do not use the GUIDs directly. Instead you can use the ConnMgrMapURL function to determine the appropriate network GUID.

The Connection Manager encapsulates the logic to determine which network a specific URL requires. So rather than hard-code a specific network GUID in your application, you simply pass the destination URL to the ConnMgrMapURL function and the function returns the appropriate GUID.

Note

The Connection Manager determines whether a URL requires the Internet or the Work network (intranet) based on whether the destination address contains periods in the name. Addresses that contain periods are considered to be on the Internet, addresses that do not contain periods are considered to be on the Work network. If your organization uses periods for intranet addresses, you will need to add those address to the Work URL exception list. To add URLs to the Work URL exception list, select Start on the device, choose Settings, select the Connections tab, select the Connections icon, select the Advanced tab, and then select the Exceptions button.

The following code shows an example of using the ConnMgrMapURL function to determine the destination GUIDs for different URLs.

string url1 = "https://msdn2.microsoft.com/en-us/netframework/bb495180.aspx";
string url2 = "https://hedgydev02/test/default.aspx";
Guid destination1 = Guid.Empty;
Guid destination2 = Guid.Empty;

ConnMgrMapURL(url1, ref destination1, 0);
ConnMgrMapURL(url2, ref destination2, 0);

// Write to debug window
Debug.WriteLine(url1);
Debug.WriteLine(destination1.ToString());
Debug.WriteLine("");
Debug.WriteLine(url2);
Debug.WriteLine(destination2.ToString());

In the sample, there are two URLs. The first URL points to a location on Microsoft's MSDN® Web site, which is of course on the Internet. The other URL points to one of the computers on the internal network and therefore is located on the Work network. Figure 1 shows the information that appears in the Visual Studio Output window when you run this code. As you can see, the Microsoft URL returns the Internet GUID (436EF144-B4FB-4863-A041-8F905A62C572) whereas the URL pointing the internal network returns the Work GUID (A1182988-0D73-439e-87AD-2A5B369F808B).

Bb840031.2c69b0cb-8f0f-4cef-b578-9b15755bb096(en-us,MSDN.10).gif

Figure 1. The destination network identifiers for an Internet URL and a Work URL

Thanks to the ConnMgrMapURL function, this may be the last time you ever have to see those GUIDs. In the future, you can just let the ConnMgrMapURL function figure out the GUIDs for you.

Making the Connection

From this point, making the connection simply requires you to create an instance of the ConnMgrConnectionInfo class with the appropriate connection criteria, and call the appropriate Connection Manager function.

When you make the connection request you can use either the ConnMgrEstablishConnectionSync function, which blocks until the connection process completes or you can use the ConnMgrEstablishConnection function, which returns immediately and establishes the connection without requiring the calling thread to wait for the connection process to complete. If your application is running in the background or if you are establishing the connection on a background thread, the ConnMgrEstablishConnectionSync function is easy to work with because you know as soon as the function returns whether you have successfully established a connection. The following code sample demonstrates using the ConnMgrEstablishConnectionSync function to establish a connection.

IntPtr _connectionHandle = IntPtr.Zero; // Class-level field
const int _syncConnectTimeout = 60000; // 60 seconds
void DoConnect(string url)
{
    Guid networkGuid = Guid.Empty;
    ConnMgrStatus status = ConnMgrStatus.Unknown;
    ConnMgrMapURL(url, ref networkGuid, 0);
    ConnMgrConnectionInfo info = new ConnMgrConnectionInfo(networkGuid, ConnMgrPriority.HighPriorityBackground);
    ConnMgrEstablishConnectionSync(info, ref _connectionHandle, _syncConnectTimeOut, ref status);

    if (status == ConnMgrStatus.Connected)
        Debug.WriteLine("Connect Succeeded");
    else
        Debug.WriteLine("Connect failed: " + status.ToString()); 
}

Notice that the preceding code passes a timeout value to the ConnMgrEstablishConnectionSync function. You should provide a substantial value for the timeout because establishing connections, especially in places with poor network coverage, can sometimes take many tens of seconds. If the function returns because the timeout expires, as opposed to because of a connection error, the status value is ConnMgrStatus.WaitingConnection. When you receive the ConnMgrStatus.WaitingConnection status value, chances are that the connection could have succeeded given enough time; therefore, you should try to make the connection using a longer timeout value.

To test the preceding connection code, use the Windows Mobile 6 Professional Device Emulator and Cellular Emulator. The Cellular Emulator acts as a virtual cellular radio for the Device Emulator providing the Device Emulator with General Radio Packet Service (GPRS) connectivity. To get started, you must first connect the Device Emulator to the Cellular Emulator by following the instructions in the Cellular Emulator section of the Developer's Guide to the Arm Emulator.

You also need to define GPRS connections for the emulator. This is the same process you follow to define a GPRS connection on a physical device to connect to your service provider's network. Follow these steps to define the GPRS Internet connection.

  1. Within the Device Emulator select Start, and then select Settings.
  2. On the Settings screen, select the Connections tab.
  3. Select the Connections icon.
  4. On the Connections screen, select Add a new modem connection immediately below the heading My ISP.
  5. Name the connection GPRS Internet. The name has no affect on the connection behavior.
  6. Select Cellular (GPRS) from the Select a modem drop-down list.
  7. Select Next.
  8. Leave the Access point name field blank and select Next.
  9. Leave all of the fields blank (User name, Password, Domain) and select Finish.

You now have a GPRS connection defined for the Internet. To define a GPRS connection for your Work network, follow these same steps except this time in step 4 select Add a new modem connection immediately under My Work Network, and in step 5 name the connection GPRS Work.

Note

The reason that you are able to leave the Access point and login information blank is because you are connecting through the Cellular Emulator. On an actual device, you would need to provide the information for these fields as defined by your service provider.

When you run the preceding code, you should notice that after a few seconds the Cellular Emulator shows activity on one of the Network Channels as shown in Figure 2.

Bb840031.837f16b6-74c8-4911-97b0-276400ed7445(en-us,MSDN.10).gif

Figure 2. The Cellular Emulator with an active GPRS connection

A few seconds after the Cellular Emulator shows activity, the ConnMgrEstablishConnectionSync function should return. You always want to check the returned status value to verify that the connection is successful. A successful connection returns a status of ConnMgrStatus.Connected.

Note

To close the Cellular Emulator's connection, on the Network tab of the Cellular Emulator, click the Disconnect GPRS button.

Because the ConnMgrEstablishConnectionSync function blocks until the connection process is complete, it is not appropriate for connections that your application initiates on the main thread of a user-oriented application. Using the ConnMgrEstablishConnectionSync function in this way will cause your application user interface to freeze until the connection request completes. To avoid freezing the application user interface, use the ConnMgrEstablishConnection function. The ConnMgrEstablishConnection function does not wait for the connection process to complete but rather initiates the connection request then returns immediately. As the following code shows, calling the ConnMgrEstablishConnection function is very much like calling the ConnMgrEstablishConnectionSync function.

Guid networkGuid = Guid.Empty;
ConnMgrMapURL(url, ref networkGuid, 0);
ConnMgrConnectionInfo info = new ConnMgrConnectionInfo(networkGuid);
ConnMgrEstablishConnection(info, ref _connectionHandle);

The call to the ConnMgrEstablishConnection function in the preceding code initiates the connection process but returns before the Connection Manager actually establishes the connection. To determine when the connection completes, you can use the SystemState class in conjunction with the ConnMgrConnectionStatus function.

The following code shows how to set up the SystemState class to notify your application when the number of active connections changes.

SystemState _connectionsCount;
private void Form1_Load(object sender, EventArgs e)
{
    _connectionsCount = new SystemState(SystemProperty.ConnectionsCount);
    _connectionsCount.Changed += new ChangeEventHandler(ConnectionsCount_Changed);
} 

In the preceding code, the program constructs the _connectionsCount instance and associates it with the ConnectionsCount state value. By then associating the ConnectionsCount_Changed method with the _connectionsCount.Changed event, the _connectionsCount instance will call the ConnectionsCount_Changed method anytime the number of active connections changes.

Once you know that the number of active connections has changed, you need to determine if the change is caused by the connection you requested. The following code demonstrates using the ConnMgrConnectionStatus function to determine if that change is caused by successfully establishing the connection you requested in your earlier call to the ConnMgrEstablishConnection function.

void ConnectionsCount_Changed(object sender, ChangeEventArgs args)
{
    ConnMgrStatus status = ConnMgrStatus.Unknown;
    ConnMgrConnectionStatus(_connectionHandle, ref status);
    if (status == ConnMgrStatus.Connected)
    {
        // Connection Established
    }
} 

As you can see in the preceding code, if the connection status is ConnMgrStatus.Connected, you know your connection is ready and you can begin using it. One thing to keep in mind is that the system calls the ConnectionsCount_Changed method on the main application thread; therefore, you do not want to perform any long-running tasks from within this method. Instead you should perform the task either on a background thread or by using an asynchronous method such as the SqlCeReplication class' BeginSynchronize method.

You can test this code using the Device Emulator and Cellular Emulator just as you did earlier when testing the ConnMgrEstablishConnectionSync function.

Note

A number of options exist for determining the current status of a connection. You can use the ConnMgrConnectionStatus function to check the status of the connection at any time, which you may find useful for verifying that the connection has not encountered unexpected problems. You can also create the MessageWindow-derived class and set the ConnMgrConnectionInfo class' hWnd field to the MessageWindow-derived class' window handle; in this case the Connection Manager will send a message to the MessageWindow-derived class each time the connection status changes. You can also use the ConnMgrRegisterForStatusNotification function.

Releasing the Connection

The process of releasing a connection is pretty straightforward. For the most part, you simply the call the ConnMgrReleaseConnection function passing the connection handle returned from either the ConnMgrEstablishConnectionSync function or the ConnMgrEstablishConnection function. The ConnMgrReleaseConnection function signals the Connection Manager that your application is done with the connection but the function does not necessarily close it. To understand when connections are actually closed, you need to understand the affect of the ConnMgrReleaseConnection function's cache parameter and how the Connection Manager manages connection caching.

Caching the Connection

As you know, establishing a connection can be time consuming. To avoid the overhead of re-establishing the same connection repeatedly, the Connection Manager may maintain a connection even after the last application has released the connection. This is known as connection caching. Applications can influence the length of time the Connection Manager caches a connection through the cache parameter of the ConnMgrReleaseConnection function but the Connection Manager has ultimate authority. Table 4 shows the list of possible cache parameter values and their meaning.

Table 4. ConnMgrReleaseConnection cache parameter values

Parameter Value Description

0

Do not cache the connection

1

Cache the connection for the default amount of time

Greater than 1

Cache the connection for this number of seconds

As shown in Table 4, you can request that the Connection Manager close the connection immediately by passing a cache parameter value of 0. To request that the Connection Manager cache the connection for the default period of time, pass a cache parameter value of 1 as shown in the following code sample.

// Release the connection and cache it for the default time period.
ConnMgrReleaseConnection(_connectionHandle, 1);

The default connection cache times are defined as named values in the registry under the HKEY_LOCAL_MACHINE\Comm\ConnMgr\Planner\Settings registry key. The default cache time for a connection depends on whether the connection is created as an exclusive connection. The CacheTime named registry value defines the default cache time for non-exclusive connections. The CacheTime named registry value is set to 600 seconds (10 minutes) on most devices. For exclusive connections, the VPNCacheTime named registry value defines the cache time, which is 60 seconds (1 minute) on most devices.

Note

An exclusive connection is a connection that cannot be used by any application other than the application that creates the connection. You create an exclusive connection by setting the ConnMgrConnectionInfo.bExclusive field to a non-zero value. In most cases, you can make most efficient use of device resources by allowing connections to be shared (that is, non-exclusive).

Prior to Windows Mobile 5.0, an application could only specify whether or not a connection was cached. With Windows Mobile 5.0 and continuing with Windows Mobile 6, you can specify the amount of time you would like the Connection Manager to cache the connection. You do this by simply passing the desired number of seconds to cache the connection rather than passing a 0 or a 1 to the cache parameter. For example, the following code shows how to release the connection and request that the Connection Manager cache the connection for 5 minutes (300 seconds).

// Release the connection and cache it for 5 minutes.
ConnMgrReleaseConnection(_connectionHandle, 300);

You should always remember that the value that your application passes to the ConnMgrReleaseConnection function's cache parameter is simply a request. The Connection Manager may choose to ignore that request. Most commonly when the Connection Manager overrides your caching request, the Connection Manager keeps the connection cached longer than requested. One case where this happens is when the device has a constant connection, such as when connected to the network via Ethernet cable or when the device is cradled and is using desktop pass-through networking through ActiveSync. In these types of connections, the actual network connection is established physically through a network cable or by a cradled device; they remain connected until physically disconnected. The Connection Manager manages these connections but does not actually open or close them.

Another case where the Connection Manager may cache the connection longer than your application requests is when there is no cost to maintaining the connection. The most common example is a GPRS connection. GPRS radios do not consume power except when actually transferring data, and in most cases mobile operators bill GPRS connections based on data transfer volume not the amount of time connected.

You can see the Connection Manager's caching behavior of GPRS connections with the Cellular Emulator. To do so, verify that the Device Emulator and Cellular Emulator are still properly connected. If the Cellular Emulator still has an active connection, close the connection by clicking Disconnect GPRS on the Cellular Emulator's Network tab. Now run the following code.

Guid networkGuid = Guid.Empty;
ConnMgrStatus status = ConnMgrStatus.Unknown;
ConnMgrMapURL(url, ref networkGuid, 0);
ConnMgrConnectionInfo info = new ConnMgrConnectionInfo(networkGuid, ConnMgrPriority.HighPriorityBackground);
Debug.WriteLine ("Attempting Sync Connect");
ConnMgrEstablishConnectionSync(info, ref _connectionHandle, _syncConnectTimeOut, ref status);

if (status == ConnMgrStatus.Connected)
    ConnMgrReleaseConnection(_connectionHandle, 0);
else
    Debug.WriteLine("Connection failed: " + status.ToString());

The preceding code is the code from the earlier ConnMgrEstablishConnectionSync function example code with a call to the ConnMgrReleaseConnection function added at the end. Notice that the call to the ConnMgrReleaseConnection function passes 0 to the cache parameter requesting that the Connection Manager immediately close the connection.

When you run the code, you will notice that the Cellular Emulator shows that the connection becomes active just as it did previously. Notice though that the connection never terminates; the value in the Time(s) column keeps incrementing. The connection remains established but it is not transferring any data, and on a real device it does not consume any power in this state. The Connection Manager is overriding the request to not cache the connection but doing so does not consume any significant resources.

This type of connection is sometimes called a suspend/resume connection indicating that when not in use, the connection can remain connected but go into an efficient suspended state. This GPRS connection may remain connected indefinitely but will not be active until the Connection Manager returns the connection to an application and the application uses it.

Conclusion

The Connection Manager is one of the most powerful features of Windows Mobile. It encapsulates the details of managing connections, selecting the best available connection, and even handles connection sharing across applications. It supports a wide variety of features, which sometimes intimidates users but as you have seen, most applications do not need to be concerned about the Connection Manager's extended features. Using just a few functions, you can easily establish a connection leaving the Connection Manager to handle the underlying details.

See Also

Other Resources

Connection Manager Reference
Windows Mobile Cellular Emulator
Windows Mobile Device Emulator

Jim Wilson is president of JW Hedgehog, Inc. (https://www.jwhh.com) a New Hampshire–based consulting firm specializing in solutions, content creation, and mentoring for the Windows Mobile platform. Jim has worked extensively with the .NET Framework and .NET Compact Framework since the original beta release of each; he has over 20 years experience in the software industry including more than 14 years experience with relational database programming including SQL Server and SQL Server Compact Edition. Jim writes frequently for MSDN and has developed mobility curriculums for two of the industry’s leading technology training organizations, DevelopMentor and PluralSight. Jim speaks regularly at Tech Ed, the Professional Developer's Conference (PDC), VSLive, and the Mobility & Embedded DevCon. You will find Jim online at https://pluralsight.com/blogs/jimw.