Remote Access Services (RAS)

The Remote Access Service (RAS) functions can be used to make a connection using a pre-defined RAS phone book entry. RAS will make the call, logon to the remote computer, handle authentication, and then negotiate network connections. You can use RAS connections to do the following:

Dial into a Windows NT or 2000 RAS-enabled server, and then use TCP/IP using Point to Point Protocol (PPP) to connect to file shares, printers, intranet, email server, or other resources. The Windows NTLM (NT LAN Manager) authentication will be handled by RAS.

Dial into an Internet Service Provider (ISP), and then use TCP/IP using Point to Point Protocol (PPP) to connect to the Internet or email. RAS will usually handle the logon and authentication required by the ISP.

RAS maintains a phone book with entries for each available connection. Users can manage this phone book using the Connections folder on the desktop. Each phone book entry has an associated name and information on how the connection should be made (such as the phone number, login credentials, and protocols to use). Standard RAS phone book entries are preinstalled to support the connection to desktop PCs, such as "Serial Port @ 19200."

Unlike TAPI, an application does not directly use the connection itself. Instead, it uses the TCP/IP network protocol through the connection managed by RAS. You can use RAS in your own applications to make a connection to aserver, and then use network techniques such as HTTP and sockets to communicate with the server (see Chapter 8). Alternatively, you can check whether a RAS connection is already made, and then use the existing connection if it is the server to which you require access. Note that RAS in Windows CE only supports a single connection at any one time, and does not support incoming connections. This means that, if a Windows CE device is currently connected to a desktop PC, RAS cannot be used to dial out through, for example, a modem.

In Windows CE the phone book is stored in the registry and not in files as is the case with Windows NT/98/2000. The key HKEY_CURRENT_USERCommRasBook has a sub-key for each of the entries, such as "115200 Default." These sub-keys have values specifying the connection parameters, such as "User,""Domain," and "Password" (which is encrypted).

Listing RAS Phone Book Entries

The names of all the RAS phone book entries can be obtained through a call to the function RasEnumEntries (Table 11.9). To call this and any other RAS function, you should include ras.h for function prototypes and constants, and raserror.h for error codes.

Table 11.9. RasEnumEntries—Retrieves all RAS phone book entries
RasEnumEntries
LPWSTR ReservedPass as NULL.
LPWSTR lpszPhoneBookPathIn Windows CE the Phone Book is stored in the registry, so pass as NULL.
LPRASENTRYNAME lprasentrynamePointer to an array of RASENTRYNAME structures that will receive information on the RAS phone book entries.
LPDWORD lpcbSize of the array pointed to by LPRASENTRYNAME in bytes.
LPDWORD lpcEntriesPointer to a DWORD that contains the number of returned phone book entries.
DWORD Return Value0 for success, or an error code defined in the header file raserror.h.

An application calling RasEnumEntries should first allocate an array of RASENTRYNAME structures with enough elements to hold the expected number of phone book entries. The RASENTRYNAME structure has only two members:

  • dwSize—The size of the structure in bytes

  • szEntryName—A buffer in which the phone book entry name (e. g. "115200 Default") is placed

Before calling RasEnumEntries, the first element in the RASENTRYNAME array should have the dwSize member set to the size of a single RASENTRYNAME structure. In Listing 11.6, an array of 20 RASENTRYNAME structures is allocated, the first member is set to the size of the structure, and the dwSize variable is set to the overall size of the array in bytes. A call to RasEnumEntries is then made. A "for" loop is used to display the entry name for all the returned phone book entries

Listing 11.6. Listing RAS phone book entries
#include <ras.h>
#include <raserror.h>
void Listing11_6()
{
  LPRASENTRYNAME lpRasEntry = NULL;
  DWORD dwRes, dwSize, dwEntries, dw;
  lpRasEntry = new RASENTRYNAME[20];
  if(lpRasEntry == NULL)
  {
    cout ≪ _T("Out of memory") ≪ endl;
    return;
  }
  lpRasEntry[0].dwSize = sizeof(RASENTRYNAME);
  dwSize = sizeof(RASENTRYNAME) * 20;
  dwRes = RasEnumEntries(NULL, NULL, lpRasEntry,
          &dwSize, &dwEntries);
  if (dwRes != 0)
    cout ≪ _T("Error getting RAS entries")
         ≪ dwRes≪ endl;
  else
  {
    for(dw = 0; dw < dwEntries; dw++)
    {
      cout ≪ lpRasEntry[dw].szEntryName ≪ endl;
    }
  }
  delete[] lpRasEntry;
}

It is possible that more RAS phone book entries exist than will fit in the supplied array. RasEnumEntries is meant to return an ERROR_BUFFER_TOO_SMALL error, and only return the number of entries that fit in the array. However, in Windows CE RasEnumEntries returns a "0" value for success even if all the entries cannot be returned. So, if your array is completely full on a return from RasEnumEntries, you should reallocate the array to make it larger and call RasEnumEntries again to ensure that all the entries are returned.

Making a RAS Connection

Connecting using RAS involves two steps:

  • Setting the connection parameters, such as the login name, telephone number, and domain name

  • Making the call using the RasDial function

The easiest way of setting the connection parameters is to call the RasGetEntryDialParams (Table 11.10) function to retrieve settings from the registry for the given phone book entry. You can then either use the default values or change them appropriately. The RASDIALPARAMS structure can be passed to RasDial to actually make the connection.

Table 11.10. RasGetEntryDialParams—Retrieves default connection settings for a phone book entry
RasGetEntryDialParams
LPWSTR lpszPhoneBookName of the phone book entry, such as "115200 Default"
LPRASDIALPARAMS lpRasDialParamsPointer to a RASDIALPARAMS structure to receive the connection settings
LPBOOL lpfPasswordTRUE if the password was returned, FALSE if it needs to be supplied
DWORD Return Value0 for success, or an error code defined in the header file raserror.h

The RASDIALPARAMS structure contains members for the essential parameters for making a connection. The most important ones are the following:

  • dwSize—Size of the array in bytes. This should be initialized before calling RasGetEntryDialParams.

  • szEntryName—The phone book entry name, e.g. "115200 Default."

  • szUserName—Name used for logon.

  • szPassword—Password used for logon. This will need to be set if lpfPassword is FALSE on return from RasGetEntryDialParams.

  • szDomain—Domain used for authentication.

The RAS connection is made by calling the RasDial function ( Table 11.11). This function is passed a RASDIALPARAMS structure and returns a HRASCONN connection handle. The function makes the call asynchronously—it returns before the connection has been made. Usually, an application will request that notifications through a WM_RASDIALEVENT message be sent to a designated window, as described in the next section.

Table 11.11. RasDial—Makes a RAS connection
RasDial
LPRASDIALEXTENSIONS dialExtensionsNULL for Windows CE.
LPTSTR phoneBookPathNULL for Windows CE. The Phone Book is in the registry.
LPRASDIALPARAMS rasDialParamRASDIALPARAMS structure returned through calling RasGetEntryDialParams.
DWORD NotifierTypeHow to notify application of dialing progress. 0 for no notification, or 0xFFFFFFFF to indicate that the "notifier" parameter contains a window handle to receive a WM_RASDIALEVENT message.
LPVOID notifierPointer to a hWnd to receive WM_RASDIALEVENT messages, or NULL for no notification.
LPHRASCONN pRasConnPointer to a HRASCONN variable to receive a RAS connection handle.
DWORD Return Value0 for success, or an error code defined in the header file raserror.h.

In Listing 11.7a, the RasGetEntryDialParams and RasDial functions are used to make a connection. Note that RasDial will fail with an error 602 if there is already a RAS connection. The function Listing11_7 is passed the window handle of the main application window, and this is used for notification.

Listing 11.7a. Making a connection using RAS
HRASCONN g_hRasConn = NULL;
// NB: Assumes that a RAS connection (such as ActiveSync)
// is not already open. If this is the case, RasDial
// returns an error 602.
void Listing11_7(HWND hWnd)
{
  RASDIALPARAMS rasDialParams;
  DWORD dwRes;
  BOOL bPassword;
  rasDialParams.dwSize = sizeof(RASDIALPARAMS);
  // change "SPL" to your RAS entry name
  wcscpy(rasDialParams.szEntryName, _T("SPL"));
  dwRes = RasGetEntryDialParams(NULL,
      &rasDialParams, &bPassword);
  if(dwRes != 0)
  {
    cout ≪ _T("Error getting Dial Params:")
         ≪ dwRes endl; ≪ return;
  }
  if(!bPassword)
    cout ≪ _T("Password not returned") < endl;
  dwRes = RasDial(NULL, NULL, &rasDialParams,
      0×FFFFFFFF, hWnd, &g_hRasConn);
  if(dwRes != 0)
    cout ≪ _T("Error dialing RAS: ")
       ≪ dwRes ≪ endl;
}

Monitoring a RAS Connection

An application can specify a window handle that will receive WM_RASDIALEVENT messages so that the progress of a connection can be monitored. The code in Listing 11.7b lists the function RasDialEvent that is called from the main window message procedure when a WM_RASDIALEVENT is called. The wParam value contains a value defined in the RASCONNSTATE enumeration. The code in Listing 11.7b shows some of the more important event numbers, such as connection and disconnection. An application should wait until a RASCS_Authenticated event has been received—this indicates that the connection has been made, the user has been authenticated, and a network connection is present.

Listing 11.7b. Responding to WM_RASDIALEVENT
// This function is called from the message-processing
// function for the windows with the hWnd handle passed
// to RasDial. See code in Examples.cpp relating to the
// WM_RASDIALEVENT message
void RasDialEvent(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
  if(wParam == RASCS_OpenPort)
    cout ≪ _T("Opening Port") ≪ endl;
  else if(wParam == RASCS_PortOpened)
    cout ≪ _T("Port Opened") ≪ endl;
  else if(wParam == RASCS_ConnectDevice)
    cout ≪ _T("Connecting to device")≪ endl;
  else if(wParam == RASCS_DeviceConnected)
    cout ≪ _T("Connected") ≪ endl;
  else if(wParam == RASCS_Authenticated)
    cout ≪ _T("Authenticated") ≪ endl;
  else if(wParam == RASCS_DeviceConnected)
    cout ≪ _T("Connected") ≪ endl;
  else if(wParam == RASCS_AllDevicesConnected)
    cout ≪  _T("All devices connected") ≪ endl;
  else if(wParam == RASCS_Authenticate)
    cout ≪ _T("Waiting for authentication") ≪ endl;
  else if(wParam == RASCS_AuthAck)
    cout ≪ _T("Authentication acknowledged") ≪ endl;
  else if(wParam == RASCS_Disconnected)
    cout ≪ _T("Disconnected") ≪ endl;
}

Dropping a RAS Connection

An application can drop a RAS connection through calling the RasHangUp function, and passing the HRASCONN returned from calling RasDial. A RAS connection is not owned by any one particular application, so the RAS connection is not automatically dropped when the application that made the connection terminates. Also, as described in the next section, an application can use a connection already made by another application.

Listing 11.8. Dropping a RAS connection
void Listing11_8()
{
  if(g_hRasConn != NULL)
  {
    RasHangUp(g_hRasConn);
    g_hRasConn = NULL;
  }
  else
    cout ≪ _T("Not connected") ≪ endl;
}

Testing for an Existing RAS Connection

An application should test for an existing RAS connection before attempting tomake a new connection since Windows CE only supports a single connection at any one time. If a connection already exists, the application should test whether the connection is to the correct server for its requirements.

The RasEnumConnections (Table 11.12) function returns information about a RAS connection, if one exists. On the desktop, this function can return information about more than one connection, but on Windows CE it can only ever return information about a single connection, as this is the maximum number of supported connections.

In Listing 11.9 an array of RASCONN structures is passed into the function RasEnumConnections. The dwSize member of the first RASCONN structure must be initialized with the size of the array prior to calling the function. On return, the dwConnections variable contains the number of active RAS connections. The RASCONN structure contains the following members:

  • dwSize—The size in bytes of the structure

  • hrasconn—The RAS connection handle, as returned from RasDial

  • szEntryName—The RAS phone book entry name

Table 11.12. RasEnumConnections
RasEnumConnections
LPRASCONN lprasconnArray of RASCONN structures into which information about the connections is returned.
LPDWORD lpcbPointer to a DWORD that contains, on calling the function, the size of the array pointed to be lpcConnections. On return, it contains the number of bytes returned in lpcConnections.
LPDWORD lpcConnectionsPointer to a DWORD that returns the number of RASCONN structures returned in lprasconn.
DWORD Return Value0 for success, or an error code defined in the header file raserror.h.

If a connection exists, the RasGetConnectStatus function is used to return a RASCONNSTATUS structure for the hrasconn handle. The rasconnstate member contains the value from the RASCONNSTATE enumeration, which is the same enumeration used with the WM_RASDIALEVENT message in Listing 11.7b.

Listing 11.9. Testing for existing RAS connection
void Listing11_9()
{
  RASCONN rsconn[10];
  DWORD dwcb, dwConnections;
  RASCONNSTATUS rasStatus;
  dwcb = sizeof(rsconn);
  rsconn[0].dwSize = sizeof(RASCONN);
  if(RasEnumConnections(rsconn, &dwcb, &dwConnections)
      == 0)
  {
    if(dwConnections == 0 ||
        rsconn[0].hrasconn == NULL)
    {
      cout ≪ _T("No current connections")
           ≪ endl;
      return;
    }
    // Find the current status of the RAS connection
    // Note there will only ever be one connection
    rasStatus.dwSize = sizeof(rasStatus);
    if(RasGetConnectStatus(rsconn[0].hrasconn,
        &rasStatus) != 0)
    {
      cout ≪ _T("Could not get status")
        ≪ endl;
      return;
    }
    if(rasStatus.rasconnstate != RASCS_Connected)
    {
      cout ≪ _T("Not connected") ≪ endl;
      return;
    }
    cout ≪ _T("Current connection to: ")
         ≪ rsconn[0].szEntryName;
  }
  else
    cout ≪ _T("Could not enumerate RAS connections")
          ≪ endl;
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.174.168