Differences in Connection Manager from Windows Embedded CE 6.0 R3 to Windows Embedded Compact 7
3/12/2014
Connection Manager in Windows Embedded Compact 7 is different than in previous versions.
Core Connection Manager Redesign
In Windows Embedded CE 6.0 R3, Connection Manager used destination networks, or "meta-networks", to categorize URLs. Connection Manager associated each configured underlying network interface. Some examples are: GPRS and Wi-Fi, with a meta-network; a GPRS connection connected to the Internet; or a Wi-Fi connection connected to a corporate WLAN. Not only is this approach confusing, it does not support all possible network topologies.
In Windows Embedded CE 6.0 R3, applications had to call Connection Manager APIs for their basic connectivity requirements. Generally, applications should be able to leverage the connection selection mechanism that Connection Manager offers without directly calling the Connection Manager APIs.
In Windows Embedded Compact 7, the concept of meta-networks is removed; instead, Connection Manager functionality is exposed through existing network APIs like Winsock and WinInet.
Connection Policy Management
In Windows Embedded CE 6.0 R3, the Connection Planner used default cost, bandwidth, and latency metrics for connection type-for example, GPRS, Wi-Fi, and DTPT-to determine the type of connection preferred when multiple connections are available. This default hard-coded metrics model limited the functionality of Connection Manager. In Windows Embedded Compact 7, the new Connection Policy Management provides Connection Manager with the capability to configure global, per-application, per-host policies for selecting one connection over other.
Decoupling from Shell
The Windows Embedded CE 6.0 R3 Connection Manager was tightly coupled with Windows Embedded Compact Shell. Connection Manager relied on Shell to detect connections and receive configuration. In Windows Embedded Compact 7, Connection Manager detects and autoconfigures connections instead of receiving the information from Shell.
Resource Manager
In Windows Embedded CE 6.0 R3, Connection Manager determined whether resources were available or if there was a resource conflict. This resource information is highly specific to the network accessed and dynamically changes as a device moves in and out of different coverage areas with different capabilities. In Windows Embedded Compact 7, information about specific resources and how they interact is moved from the Connection Manager to a new Resource Manager. Resource Manager improves the flexibility of Connections Manager to work with any type of network resource by abstracting the concept of resources from Connection Manager to Resource Manager.
There are two key differences between Windows Embedded CE 6.0 R3 and Windows Embedded Compact 7 resource management.
- In Windows Embedded CE 6.0 R3, applications selected their own priority. This made it difficult for system administrators to control which application had priority at any given time. In Windows Embedded Compact 7, applications can only assign priority in intra-application conflicts; they cannot assign priorities for conflicts between applications.
- The Resource Manager can be extended with Resource Service Providers (RSPs) RSPs enable greater flexibility in handling resource conflicts between new connection types.
Connection Manager Backward Compatibility Support
Backward compatibility focuses on the support of applications that use legacy Connection Manager APIs to connect to the Internet and retrieve data by using WinInet.
Legacy APIs from Windows Embedded CE 6.0 R3 are supported but the connection is established when the WinINet APIs are called. Some application using legacy APIs may not work. Backward compatibility is at risk for applications that:
- Depend on custom meta-networks
- Depend on complex status transitions for legacy Connection Manager connection requests, for example, suspended and waiting-for-phone,
- Get proxy information from legacy Connection Manager and handle proxies internally, not through WinINet
- Use ConnMgrMapConRef
- Use ConnMgrQueryDetailedStatus
- Use ConnMgrRegisterForStatusChangeNotification
- Use ConnMgrRegisterScheduledConnection
Connection Manager API Migration
You can develop and port your existing applications that use legacy Connection Manager to Windows Embedded Compact 7 by using the Windows Embedded Compact 7 Connection Manager APIs or by using WinINet or WinSock.
WinINet Client
An application does not need to call ConnMgrEstablishConnection. The following code snippet is an example of using the WinInet client.
HINTERNET hInet = InternetOpenW(...);
HINTERNET hConn = InternetConnectW(...);
CM_SESSION_HANDLE hSess = NULL;
DWORD cbSess = sizeof(hSess);
BOOL fRet = InternetQueryOptionW(
hConn,
INTERNET_OPTION_CM_HANDLE_COPY_REF,
(LPVOID)&hSess,
&cbSess);
// Optional: Set priority, requirements, preferences for CM session.
CmCloseSession(hSess);
HINTERNET hReq = NULL;
BOOL fRet = HttpSendRequestW(&hReq, ...);
while (InternetReadFile(hReq, …))
{
// TODO: Process data.
}
// TODO: Cleanup.
Setting priority, requirements, and preferences
The following code snippet is an example of setting priority, requirements, and preferences.
CM_SESSION_HANDLE hSess = NULL;
// TODO: Obtain CM session.
CM_RESULT cmRes = CmSetPriority(
hSess, CM_PRIORITY_BACKGROUND_HIGHEST);
CM_REQUIREMENTS Reqs;
Reqs.Version = CM_CURRENT_VERSION;
Reqs.cRequirement = 1;
Reqs.Requirement[0].Characteristic = CMCH_ROAMING;
Reqs.Requirement[0].Operator = CMRO_EQUAL;
Reqs.Requirement[0].Value = 0; // Not roaming.
CM_RESULT cmRes = CmSetRequirements(hSess, &Reqs, sizeof(Reqs));
CM_PREFERENCES Prefs;
Prefs.Version = CM_CURRENT_VERSION;
Prefs.cPreference = 1;
Prefs.Preference[0].Characteristic = CMCH_BANDWIDTH_KBITPS;
Prefs.Preference[0].Operator = CMPO_HIGHEST;
CM_RESULT cmRes = CmSetPreferences(hSess, &Prefs, sizeof(Prefs));
CmCloseSession(hSess);
Winsock TCP Client
An application does not need to call ConnMgrEstablishConnection and ConnMgrReleaseConnection. The following code snippets are examples of using a WinSock TCP client.
SOCKET s = socket(
AF_UNSPEC, SOCK_STREAM, IPPROTO_IP);
CM_SESSION_HANDLE hSess =
WSAGetCmSession(s);
// Optional: Set priority, requirements, preferences.
CmCloseSession(hSess);
BOOL fRet = WSAConnectByNameW(
s,
pszHost,
pszService,
NULL, NULL, NULL, NULL, NULL, NULL);
if (fRet)
{
// TODO: Send/receive data.
}
Explicit Connection Selection
Winsock UDP Client
The following code snippet is an example of using a Winsock UDP client.
// TODO: WSAStartup.
CM_SESSION_HANDLE hSess = CmCreateSession();
// TODO: Set priority, requirements, preferences for CM session.
CM_CONNECTION_HANDLE hConn = NULL;
CM_RESULT cmRes = CMRE_UNEXPECTED;
for (cmRes = CmGetFirstCandidateConnection(
hSess, pszHost, CMSO_DEFAULT, &hConn);
cmRes == CMRE_SUCCESS;
cmRes = CmGetNextCandidateConnection(hSess, &hConn))
{
cmRes = CmAcquireConnection(hConn);
if (cmRes != CMRE_SUCCESS) continue;
// TODO: Attempt to connect socket over CM connection
cmRes = CmAcquireConnection(hConn);
if (cmRes != CMRE_SUCCESS) continue;
CM_ADDRESS_PAIR Addr = { CM_CURRENT_VERSION };
DWORD cbAddr = sizeof(Addr);
for (cmRes = CmGetFirstIpAddr(
hConn, pszHost, AF_UNSPEC, INADDR_ANY,
(USHORT)_wtoi(pszService),
&Addr, &cbAddr);
cmRes == CMRE_SUCCESS;
cmRes = CmGetNextIpAddr(hConn, &Addr, &cbAddr))
{
SOCKET s = socket(
Addr.Src.ss_family,
SOCK_DGRAM, IPPROTO_IP);
if (s == INVALID_SOCKET) continue;
// TODO: If acquiring connection with priority
// other than default (interactive_lowest),
// also set socket’s priority to
// CM_PRIORITY_BACKGROUND_LOWEST.
if (bind(s, (sockaddr*)&Addr.Src,
sizeof(Addr.Src)) == ERROR_SUCCESS)
{
if (connect(s, (sockaddr*)&Addr.Dst,
sizeof(Addr.Dst)) == ERROR_SUCCESS)
{
// TODO: Send and receive data.
}
closesocket(s);
}
}
CmReleaseConnection(hConn);
CmCloseSession(hSess);
// TODO: Cleanup
Winsock TCP Client with Proxy Support
The following code snippet is an example of using a Winsock TCP client with a proxy.
for (cmRes = CmGetFirstCandidateConnection(hSess, pszHost, …); …)
// pszHost is the final destination host and port.
{
cmRes = CmAcquireConnection(hConn);
if (cmRes != CMRE_SUCCESS) continue;
CM_CONNECTION_DETAILS* pDetails = NULL;
// TODO: Use CmGetConnectionDetailsByHandle
to obtain pDetails data.
PS_PROXYINFO ProxyInfo = { CM_CURRENT_VERSION };
BOOL fUseProxy = false;
WCHAR* pszDestHost = pszHost;
USHORT usDestPort = (USHORT)_wtoi(pszService);
if (PsGetProxy(pDetails->szName,
PS_PROXYTYPE_SOCKS4, &ProxyInfo)
== ERROR_SUCCESS)
{
fUseProxy = true;
pszDestHost = ProxyInfo.pszServer;
usDestPort = ProxyInfo.Port;
}
// …
for (cmRes = CmGetFirstIpAddr(
hConn, pszDestHost, …, usDestPort, …); …)
{
// TODO: Handle connection to proxy or direct
// (based on fUseProxy).
//For pszDestHost use the proxy server/port if available,
otherwise, use the final destination host and port.
}
if (fUseProxy) PsFreeGetProxy(&ProxyInfo)
delete [] pDetails;
CmReleaseConnection(hConn);
}
Priority Changes on Long-lived Connections
The following code snippet is an example of priority changes.
// Acquire connection with initial priority
CM_SESSION_HANDLE hSess1 = CmCreateSession();
CmSetPriority(hSess1, CM_PRIORITY_USER_INTERACTIVE_LOWEST);
// TODO: Select working connection/address pair and connect socket.
// TODO: Use CM_PRIORITY_BACKGROUND_LOWEST for priority of socket.
// Change priority.
//
CM_SESSION_HANDLE hSess2 = CmCreateSession();
CmSetPriority(hSess2, CM_PRIORITY_BACKGROUND_HIGHEST);
// TODO: Acquire same connection as one used by hSess1 (use CmGetConnectionDetailsByHandle to
// TODO: compare connections).
// TODO: Release connection acquired in context of hSess1.
//
// Connection is now acquired with CM_PRIORITY_BACKGROUND_HIGHEST priority.
//
CmCloseSession(hSess1);
// …
CmCloseSession(hSess2);