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:
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_USER\Comm\RasBook 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 EntriesThe 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.
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:
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
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.
The RASDIALPARAMS structure contains members for the essential parameters for making a connection. The most important ones are the following:
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.
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 RASHRASCONN 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 ConnectionAn 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 ConnectionAn 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 connectionvoid Listing11_8() { if(g_hRasConn != NULL) { RasHangUp(g_hRasConn); g_hRasConn = NULL; } else cout _T("Not connected") endl; } Testing for an Existing RAS ConnectionAn 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:
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 connectionvoid 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; }
|