본문 바로가기

Software/Network

[RAS] Using Ras Part2.

March 1999
Version: 1.0 3.0

Using RAS, part 2

by Kent Reisdorph

In Using RAS, part 1, we gave you an introduction to Microsoft's Remote Access Service (RAS) API. We showed you how to make a connection, detect an existing connection, and how to enumerate active connections. Now we'll continue our discussion on RAS by covering phonebooks in more detail, including how to add, edit, and delete phonebook entries. We'll also introduce you to some of the dialogs that RAS provides for use in your applications.

Got a phonebook handy?

Windows stores dial-up networking information in phonebooks. A phonebook contains one or more phonebook entries. Each phonebook entry describes a connection to a remote machine. This connection information includes the modem used to dial, the phone number to dial, server types, allowed protocols, scripting, and so on. A user may have just one phonebook entry or may have several entries. For example, a user may regularly connect to a server at his or her office (both local and 800 numbers), to an ISP, or to a number of online services, such as AOL, CompuServe, or MSN. Each of these connections requires a separate phonebook entry. Phonebooks are handled differently on Windows NT and Windows 95/98. Under Windows NT the phonebook is a file on disk. Phonebook files have a .PBK extension. The phonebook file is a simple text file that describes each entry's properties. The phonebook file is laid out in standard Windows configuration (INI) file format. Multiple phonebooks are possible in Windows NT although, in reality, more than one phonebook is a rarity for most users. Windows NT has a default phonebook so a specific phonebook isn't required.

In Windows 95 and 98 only one phonebook exists. The phonebook isn't stored on disk, but rather is stored in the registry.

When writing applications that use RAS you must account for the fact that the user may have multiple phonebook entries. If only one entry exists in the default phonebook, you can use that entry to make a connection. If, however, more than one phonebook entry exists, you should provide a list of entries for your user to select from. Further, if you know your application will be deployed on NT machines, then you should allow the user to specify a phonebook file.

Dealing with phonebooks

The RAS API provides functions that allow you to create, edit, and delete phonebook entries. Here again, differences exist between Windows NT and Windows 95/98. The following sections describe each of these operations in detail.

Creating a phonebook entry

Creating a phonebook entry is relatively simple, particularly in Windows 95 and 98. The RasCreatePhonebookEntry function provides this service in Windows 95 and 98. In Windows NT, use the RasEntryDlg function.

Note: You can use RasCreatePhonebookEntry on Windows NT systems even though the Win32 API help suggests using RasEntryDlg (a call to RasCreatePhonebookEntry maps to RasEntryDlg on Windows NT anyway). Usually, it's wise to heed the recommendations in the Win32 API Help file. The problem in this case, however, is that use of the Windows NT dialog functions requires RASDLG.DLL.

If you build an application on NT that uses the NT functions, it may fail to load on a Windows 95 or 98 machine because RASDLG.DLL doesn't exist on these platforms. Unless your application is specifically targeting Windows NT, you should program for the lowest common denominator. In this case, that means using RasCreatePhonebookEntry instead of RasEntryDlg to create phonebook entries.

When you call RasCreatePhonebookEntry on a Windows 95 or Windows 98 machine, Windows invokes the Make New Connection Wizard. The wizard takes the user through the process of creating a new phonebook entry. This wizard is fairly basic and only asks for a connection name, modem, phone number, and country of origin. It doesn't take into account all of the possible phonebook entry options. Additional options can be set later by editing the phonebook entry (discussed in the next section).

When you call RasCreatePhonebookEntry or RasEntryDlg on a Windows NT machine, Windows will display the New Phonebook Entry dialog box. This dialog is a multi-page dialog and allows the user to specify all aspects of a dial-up connection. The same dialog is displayed regardless of whether you call RasCreatePhonebookEntry or RasEntryDlg.

When the user completes the new phonebook entry information and closes the wizard (Windows 95/98) or dialog (Windows NT) a new entry is created in the phonebook. Here's an example of how to use the RasCreatePhonebookEntry function:

RasCreatePhonebookEntry(Handle, 0);
As you can see, there's not much to it. The first parameter of this function is a handle to the dialog's owner. In this case, we're passing the form's Handle property for this parameter. The second parameter is used to specify the phonebook in which to create the new entry. In the case, of Windows 95/98 this parameter is ignored and should be 0. In Windows NT this parameter can be the path and filename of a phonebook file. If this parameter is 0 under NT, then the default system phonebook file is used. The following example shows how to use RasEntryDlg in an application targeted for Windows NT:
RASENTRYDLG r;
memset(&r, 0, sizeof(RASENTRYDLG));
r.dwSize = sizeof(RASENTRYDLG);
r.hwndOwner = Handle;
r.dwFlags = RASEDFLAG_NewEntry;
RasEntryDlg(0, 0, &r);
First, we create an instance of the RASENTRYDLG structure, zero out the memory, and set the dwSize member to the size of the structure. Next, we set the hwndOwner member to the form's Handle property. After that, we set the dwFlags member to RASEDFLAG_NewEntry to tell Windows we're creating a new phonebook entry. Finally, we call RasEntryDlg to invoke the New Phonebook Entry dialog. The first parameter of RasEntryDlg is used to specify the phonebook that the new entry will be added to. As with all of the RAS functions, if you pass 0 for this parameter Windows will use the default phonebook file. The second parameter is unused when creating a phonebook entry so we pass 0 for that parameter. The final parameter is a pointer to the RASENTRYDLG structure.

Editing an existing phonebook entry

Editing an existing phonebook entry is no more complicated than creating a new phonebook entry. This is true because Windows does most of the work by providing dialogs for editing phonebook entries. Under Windows 95 and 98, you edit phonebook entries by calling the RasEditPhonebookEntry function. You simply pass a handle to the owning application, the phonebook to use, and the name of the phonebook entry to edit. Here's an example:
RasEditPhonebookEntry(
  Handle, 0, "My Connection");
The second parameter is used to specify the phonebook in which the entry can be found. As we said earlier, this parameter is ignored under Windows 95 and 98 and should be set to 0. When you call RasEditPhonebookEntry on a Windows 95/98 system, Windows will display a multi-page dialog containing all of the entry's configuration options. When the user clicks the OK button the entry is updated in the registry.

The RasEditPhonebookEntry function can also be used under Windows NT, but, here, the Win32 API Help recommends that you use RasEntryDlg to edit phonebook entries on NT applications. A call to RasEntryDlg might look like this:

RASENTRYDLG r;
memset(&r, 0, sizeof(RASENTRYDLG));
r.dwSize = sizeof(RASENTRYDLG);
r.hwndOwner = Handle;
r.dwFlags = 0;
RasEntryDlg(0, "MyConnection", &r);
This is nearly identical to the code we used when we created a phonebook entry in the previous section. The only difference is the fact that the dwFlags parameter is set to 0 and the second parameter of RasEntryDlg specifies a phonebook entry to edit. Regardless of whether you use RasEditPhonebookEntry or RasEntryDlg on an NT system, Windows will display the Edit Phonebook Entry dialog box. This dialog is functionally identical to the New Phonebook Entry dialog box discussed in the previous section. The only difference is the dialog's title. When the user clicks the OK button, the phonebook entry is updated in the phonebook file.

Deleting phonebook entries

Deleting phonebook entries is accomplished with the RasDeleteEntry function. Using this function is ridiculously simple:
RasDeleteEntry(0, "MyConnection");
Here, we simply pass 0 for the phonebook name and "MyConnection" as the phonebook entry to delete. Windows doesn't prompt you before deleting the entry so it's up to you to provide the proper warning dialog to your user before deleting an entry from the phonebook. If you look up RasDeleteEntry in the Win32 API Help, you'll find that Help says it's only available on Windows NT. This isn't accurate. RasDeleteEntry is available on Windows 98 and on Windows 95 with service release OSR2. Be aware, though, that earlier versions of Windows 95 may not have this function.

Windows NT RAS functions

If you're writing an application that will run only on Windows NT, then you have more RAS functions available to you. Only use the RAS functions specific to Windows NT if you're certain your application will only be deployed on NT systems. Applications using the NT functions may fail to load if run on a Windows 95 or Windows 98 machine. At best they'll likely fail to operate correctly. The following RAS functions are only available on Windows NT:
RasConnectionNotification
RasDialDlg
RasEntryDlg
RasEnumAutodialAddresses
RasEnumDevices
RasGetAutodialAddress
RasGetAutodialEnable
RasGetAutodialParam
RasGetCountryInfo
RasGetCredentials
RasGetEntryProperties
RasGetSubEntryHandle
RasGetSubEntryProperties
RasMonitorDlg
RasPhonebookDlg
RasRenameEntry
RasSetAutodialAddress
RasSetAutodialEnable
RasSetAutodialParam
RasSetCredentials
RasSetEntryProperties
RasSetSubEntryProperties
RasValidateEntryName 
Some of these functions are available only on Windows NT because they're intended to be used when writing a RAS server. As such, we won't attempt to cover all of these functions in this article. There are a few, however, that we'll discuss briefly.

RasPhonebookDlg

The RasPhonebookDlg function can be used to display NT's main dial-up networking dialog box. From this dialog box, users can choose a phonebook entry to dial, can edit, copy, or delete entries, and can initiate dialing. The following example illustrates how to call RasPhonebookDlg:
RASPBDLG r;
memset(&r, 0, sizeof(RASPBDLG));
r.dwSize = sizeof(RASPBDLG);
r.hwndOwner = Handle;
RasPhonebookDlg(0, 0, &r);
The first two parameters of RasPhonebookDlg are identical to those found in RasEntryDlg. The first parameter is used to specify the phonebook file, and the second is used to specify the phonebook entry that should be initially displayed on the dialog. The final parameter is a pointer to a RASPBDLG structure.

RasDialDlg

Another NT-only function of note is the RasDialDlg function. This function will dial the specified phonebook entry and will display a simple dialog showing the connection status. A call to RasDialDlg looks like this:
RASDIALDLG r;
memset(&r, 0, sizeof(RASPBDLG));
r.dwSize = sizeof(RASDIALDLG);
r.hwndOwner = Handle;
RasDialDlg(0, "Compuserve", 0, &r);
The first two parameters are identical to those of RasPhonebookDlg. The third parameter can be used to specify a phone number to dial if you wish to override the phonebook entry's phone number. The RASDIALDLG structure is used to specify additional options for the RasDialDlg function. These additional options include the X and Y position of the dialog or a phonebook subentry to dial. On return from RasDialDlg, the dwError member can be examined to determine if an error occurred during dialing.

RasMonitorDlg

The RasMonitorDlg function is used to display a dialog showing the status of a connection. This is the same dialog box you see if you right-click the Dial-Up Networking Monitor application in NT's system tray and from the shortcut menu, choose Open Dial-Up Monitor. A call to RasMonitorDlg looks like this:
RASMONITORDLG r;
memset(&r, 0, sizeof(RASMONITORDLG));
r.dwSize = sizeof(RASMONITORDLG);
r.hwndOwner = Handle;
r.dwStartPage = 0;
RasMonitorDlg(0, &r);
The first parameter is the device the status dialog will display initially. If this parameter is 0, the status of the first device is displayed. The dwStartPage parameter of the RASMONITORDLG structure is used to specify the page of the Dial-Up Monitor dialog that's initially displayed.

Conclusion

Listing A shows the header for our test application's main unit. Listing B shows the unit itself. The test application contains a combo box that shows all of the current phonebook entries on the system. It also contains buttons that allow you to create, edit, and delete phonebook entries. You can download the code from our Web site at ftp://ftp.zdjournals.com/cpb; click on the Source Code hyperlink. Understanding the RAS API is important if you're writing applications that use dial-up networking. This is true of most Internet-based applications. Fortunately RAS isn't that difficult to use, once you have a basic understanding of how it works.

Listing A: RASPBKU.H

//---------------------------------------------
#ifndef RasPBkUH
#define RasPBkUH
//---------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *EditBtn;
	TButton *CreateBtn;
	TComboBox *EntriesCB;
	TButton *DeleteBtn;
	TLabel *Label1;
	void __fastcall EditBtnClick(TObject *Sender);
	void __fastcall 
		CreateBtnClick(TObject *Sender);
	void __fastcall FormCreate(TObject *Sender);
	void __fastcall 
		DeleteBtnClick(TObject *Sender);
  
private:	// User declarations
void EnumEntries();
public:		// User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------
#if (__BORLANDC__ < 0x530)
#define PACKAGE
#endif
extern PACKAGE TForm1 *Form1;
//---------------------------------------------
#endif
Listing B: RASPBKU.CPP
//---------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "RasPBkU.h"
#include <ras.h>
#include <raserror.h>
//---------------------------------------------
#if (__BORLANDC__ >= 0x530)
#pragma package(smart_init)
#endif
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------
void __fastcall
TForm1::EditBtnClick(TObject *Sender)
{
// Edit a phone book entry. The entry to
	// edit is the currently selected item
	// in the entries combo box.
	RasEditPhonebookEntry(
		Handle, 0, EntriesCB->Text.c_str());
}
//---------------------------------------------
void __fastcall
TForm1::CreateBtnClick(TObject *Sender)
{
	// Create a new phone book entry.
	RasCreatePhonebookEntry(Handle, 0);
	// Reset the contents of the entries combo.
	EnumEntries();
}
//---------------------------------------------
void __fastcall
TForm1::FormCreate(TObject *Sender)
{
	// Populate the combo box with a list of
	// current phonebook entries.
	EnumEntries();
}
//---------------------------------------------
void TForm1::EnumEntries()
{
	// Enumerate the entries. This is the same
	// code used in the part 1 of the RAS
	// articles so it is not explained here.
	RASENTRYNAME* entries = new RASENTRYNAME[1];
	 entries[0].dwSize = sizeof(RASENTRYNAME);
	DWORD numEntries;
	DWORD size = entries[0].dwSize;
	DWORD res = RasEnumEntries(
		0, 0, entries, &size, &numEntries);
	if (res == ERROR_BUFFER_TOO_SMALL) {
		// Allocate enough memory to get
		// all the phonebook entries.
		delete[] entries;
		entries = new RASENTRYNAME[numEntries];
		entries[0].dwSize = sizeof(RASENTRYNAME);
		res = RasEnumEntries(
			0, 0, entries, &size, &numEntries);
		if (res) {
			char buff[256];
			RasGetErrorString(
				res, buff, sizeof(buff));
			ShowMessage(buff);
		}
	}
	EntriesCB->Items->Clear();
	for (int i=0;i<(int)numEntries;i++)
		EntriesCB->
			Items->Add(entries[i].szEntryName);
	EntriesCB->ItemIndex = 0;
}

void __fastcall
TForm1::DeleteBtnClick(TObject *Sender)
{
	// About to delete an entry so display a Yes/
	// No dialog to the user for confirmation.
	char buff[256];
	wsprintf(buff,
		"Delete phonebook entry '%s'?\nWarning! "
		"Do not delete your regular dialup entry.",
		EntriesCB->Text.c_str());
	int res = MessageDlg(buff, mtConfirmation,
		TMsgDlgButtons() << mbYes << mbNo, 0);
	if (res == mrYes) {
		// OK to delete the entry.
		RasDeleteEntry(0, EntriesCB->Text.c_str());
		// Reset the list of entries in the combo.
		EnumEntries();
	}
}