Establishing GPRS Connection on Windows CE and Windows Mobile: Sample Codes

Sometimes developers asking for support have straightforward goals they want to achieve with the minimal amount of code, even if the "application" will work only on very specific scenarios. This was the case for a request I handled, where the goal was: connect the device via GPRS to Internet, when it's not cradled to a desktop PC and WiFi is not available. As you may know connections in Windows Mobile are entirely handled by the Connection Manager, and developers are "encouraged" on using only Connection Manager APIs, as long as you want CM-aware applications to run as expected. For example, IE Mobile is a CM-aware application: if you open a GPRS connection through RAS APIs as documented in the Windows *CE* documentation (see here), then Connection Manager wouldn't sense it and IE Mobile would request a new one. A well done article about this for mobile developers was written by Jim Wilson and is available here.

So, the "recommended" way on Windows Mobile is to invoke CM APIs, while on Windows CE you can use for example RAS APIs (CM is not available) - see below. Note that this code is meant to work when no other less expensive networks are available (ActiveSync\WMDC's Desktop-Passthrough, WiFi).

 #include "stdafx.h"
#include <windows.h>
#include <commctrl.h>
#include "connmgr.h"



GUID GetNetworkForURL (LPCTSTR url)
{
    DWORD dwIndex = 0;
    GUID rv;
    if (!SUCCEEDED (ConnMgrMapURL (url, &rv, &dwIndex)))
        rv = GUID_NULL;

    return rv;
}


HRESULT EstablishConnection (LPCTSTR url, DWORD retries, DWORD timeout, DWORD* dwStatus, HANDLE hConnection)
{
    CONNMGR_CONNECTIONINFO ConnectionInfo;
    ZeroMemory (&ConnectionInfo, sizeof (ConnectionInfo));
    ConnectionInfo.cbSize = sizeof (ConnectionInfo);

    ConnectionInfo.dwParams = CONNMGR_PARAM_GUIDDESTNET; 
    ConnectionInfo.dwFlags = CONNMGR_FLAG_PROXY_HTTP; 
    ConnectionInfo.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE; 
    ConnectionInfo.guidDestNet = GetNetworkForURL (url);

    return ConnMgrEstablishConnectionSync (&ConnectionInfo, &hConnection, timeout, dwStatus);
}


    //
    // Called when there was an error while connecting
    // generally due to network connection not being available (no modem, no nic etc).
    //
    HRESULT DoConnectingError(DWORD dwStatus)
    {
        // we received an error to do with connecting.
        SHELLEXECUTEINFO sei = {0};
        TCHAR szExec[MAX_PATH];
        wsprintf( szExec, TEXT("-CMERROR 0x%x -report"), dwStatus );
        sei.cbSize = sizeof(sei);
        sei.hwnd = NULL;
        sei.lpFile = TEXT(":MSREMNET");
        sei.lpParameters = szExec;
        sei.nShow = SW_SHOWNORMAL;
        ShellExecuteEx( &sei );
        return E_FAIL;
    }


int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwStatus = 0;
    HANDLE hConnection = NULL;

    LPCTSTR url = L"https://www.msn.com"; //just to set Internet network - and no need for proxies
    HRESULT hr = EstablishConnection (url, 10, 25000, &dwStatus, hConnection);

    if ( FAILED( hr ) )
    {
        DoConnectingError(dwStatus);
    }

    ConnMgrReleaseConnection(hConnection, TRUE);
    return 0;
}

 

while on Windows CE-based devices:

 //TODO: ADD ERROR-CHECKING
BOOL ConnectGPRSonWindowsCE()
{
    HRASCONN hRASConnection = NULL;
    DWORD nRet;

    RASENTRYNAME TempEntryName;
    TempEntryName.dwSize = sizeof(RASENTRYNAME);
    unsigned long EntryBufferSize = sizeof(TempEntryName);
    unsigned long EntryWritten = 0;

    //ERROR_BUFFER_TOO_SMALL is expected
    nRet = RasEnumEntries( NULL, NULL, &TempEntryName, &EntryBufferSize, &EntryWritten );
    if (nRet != ERROR_BUFFER_TOO_SMALL)
    {
        WCHAR strErr[255];
        wsprintf(strErr,L"RasEnumEntries failed: Error %d\n", nRet);
        MessageBox(NULL, (LPCTSTR)strErr, L"GPRS Monitor", MB_OK);
        return FALSE;
    }

    RASENTRYNAME *RasEntryNameArray = (RASENTRYNAME*)malloc(EntryBufferSize);
    RasEntryNameArray[0].dwSize = sizeof(RASENTRYNAME);
    nRet = RasEnumEntries( NULL, NULL, RasEntryNameArray, &EntryBufferSize, &EntryWritten );
    if (0 != nRet)
    {
        WCHAR strErr[255];
        wsprintf(strErr,L"RasEnumEntries failed: Error %d\n", nRet);
        MessageBox(NULL, (LPCTSTR)strErr, L"GPRS Monitor", MB_OK);
        return FALSE;
    }

    int GPRSEntry = -1;

    RASENTRY RasEntry;
    memset( &RasEntry, 0, sizeof(RasEntry) );
    RasEntry.dwSize = sizeof(RasEntry);
    DWORD dwEntrySize = sizeof(RasEntry);
    unsigned char Buffer[4098];
    memset( Buffer, 0, sizeof(Buffer) );
    DWORD dwBufferSize = sizeof(Buffer);

    for ( unsigned long iEntry = 0; iEntry < EntryWritten; iEntry++ )
    {
        // Check if the name has GPRS in it 
        // AND
        // if Local Phone Number contains "~GPRS!"
        nRet = RasGetEntryProperties(NULL, RasEntryNameArray[iEntry].szEntryName, &RasEntry,&dwEntrySize,NULL,NULL);
        if (0 != nRet)
        {
            WCHAR strErr[255];
            wsprintf(strErr,L"RasGetEntryProperties failed: Error %d\n", nRet);
            MessageBox(NULL, (LPCTSTR)strErr, L"GPRS Monitor", MB_OK);
            return FALSE;
        }

        if ((wcsstr(RasEntry.szLocalPhoneNumber,L"~GPRS!") != NULL) 
            &&
            (wcsstr(RasEntryNameArray[iEntry].szEntryName, L"GPRS") != NULL))
        {    
            //RAS entry is GPRS - exit 'for' loop
            GPRSEntry = iEntry;
            break;
        }
    }

    nRet = RasGetEntryProperties( NULL, RasEntryNameArray[GPRSEntry].szEntryName, &RasEntry, &dwEntrySize, Buffer, &dwBufferSize );
    if(0 != nRet)
    {
        WCHAR strErr[255];
        wsprintf(strErr,L"RasGetEntryProperties failed: Error %d\n", nRet);
        MessageBox(NULL, (LPCTSTR)strErr, L"GPRS Monitor", MB_OK);
        return FALSE;
    }

    // Configure the RASDIALPARAMS structure
    RASDIALPARAMS RASDialParameters;
    memset( &RASDialParameters,0,sizeof( RASDIALPARAMS ) );
    RASDialParameters.szPhoneNumber[0] = NULL; //TEXT('\0');
    RASDialParameters.szCallbackNumber[0] = NULL; //TEXT('\0');
    RASDialParameters.dwSize = sizeof( RASDIALPARAMS );
    wcscpy( RASDialParameters.szEntryName, RasEntryNameArray[GPRSEntry].szEntryName);
    RASDialParameters.szUserName[0] = TEXT('\0');
    RASDialParameters.szPassword[0] = TEXT('\0');
    RASDialParameters.szDomain[0] = TEXT('\0');
    //wcscpy (RasDialParams.szUserName, szUserName); //This is optional    
    //wcscpy (RasDialParams.szPassword, szPassword); //This is optional
    //wcscpy (RasDialParams.szDomain, szDomain); //This is optional


    //try reuse GPRS connection
    BOOL bPassword = FALSE;
    nRet = RasGetEntryDialParams(NULL, &RASDialParameters, &bPassword);
    if (0 != nRet)
    {
        WCHAR strErr[255];
        wsprintf(strErr,L"RasGetEntryDialParams failed: Error %d\n", nRet);
        MessageBox(NULL, (LPCTSTR)strErr, L"GPRS Monitor", MB_OK);
        return FALSE;
    }

    //free resources not on the stack
    free ((VOID*)RasEntryNameArray);
    
                
    //  Try to establish RAS connection.
    if ( RasDial( NULL, NULL, &RASDialParameters, 
            NULL, // Notifier type is NOT a window handle
            NULL, // Window receives notification message - none
            &hRASConnection ) != 0 )
    {
        if ( hRASConnection != NULL )
            RasHangUp( hRASConnection );
        hRASConnection = NULL;
        MessageBox (/*hDlgWnd*/NULL, L"Could not connect using RAS", /*szTitle*/ L"GPRS Monitor", MB_OK);
        return FALSE;
    }

    hRASConnection = NULL;
    return TRUE;

}