ITPub博客

首页 > 应用开发 > IT综合 > 有关VPN拨号上网的应用程序的开发

有关VPN拨号上网的应用程序的开发

原创 IT综合 作者:esen 时间:2010-01-26 22:53:24 0 删除 编辑
用MODEM拨号上网,仍是大多数个人网民选择上网的方式.如果能在我们的应用程序中管理拨号 网络(如Foxmail、Sygate中的拨号功能),无疑将会方便我们的软件用户(不用再切换应用程序, 运行拨号网络),提高我们的软件的友好性从而提高软件的竞争力.   在WIN9X下,如果安装了拨号网络,则在WINDOWS系统的系统目录System下将有两个拨号网络管理 程序库RasApi32.DLL和RasApi16.DLL,我们可利用其中的函数来获取和设置拨号连接网络的信息。在 Delphi帮助文件中,有相关函数的说明。    在此,我们要讨论的管理项目有: 1、获取当前系统中可用的拨号连接名称      2、新建拨号连接、修改拨号连接的属性      3、获取和设置拨号连接的拨号参数      4、用指定的拨号连接拨号、挂断指定的拨号连接      5、获取当前活动的连接及其连接状态 零、获取RasAPI函数执行失败的错误信息   RasAPI的调用接口是统一的,但对于不同的Windows版本,许多常量和数据结构的定义是不同的。 如果使用的数据结构与Windows版本不对应,RasAPI函数执行会失败;另外,其它原因如其它程序也 在使用同一个拨号连接进行拨号等,也会造成RasAPI函数执行失败.鉴于此原因,我们需要先讨论获 取RasAPI函数执行失败的错误信息的函数。 当一个RasAPI函数执行结束时,会返回一个结果标识,为0时表示执行成功,否则作为一个错误标 识符表示执行失败的原因。RasAPI函数RasGetErrorString可以根据错误标识符返回其错误描述信息, 在中文WIN9X下可提供一个中文错误信息.   RasGetErrorString的函数原型为: function RasGetErrorString ( uErrorValue : UINT;//错误标识符 lpszErrorString : PChar;//错误提示信息的缓冲区 cBufSize : DWORD//错误提示信息的缓冲区大小 ) : DWORD; stdcall; function RasGetErrorString;external RasApiDll name 'RasGetErrorStringA'; ( 注:RasApiDll = 'Rasapi32.dll'; )   为了方便,我们可以自己编写一个函数,用于获取RasAPI函数执行失败的错误信息。在下面的例 子中,会经常用到该函数。函数代码如下所示: { 根据错误标识符,获取RasAPI函数执行失败的错误信息 } function GetRasError( ErrorID : UINT ) : string; var buffer : array[ 0..255 ] of char; begin if 0 = RasGetErrorString( ErrorID, buffer, 256 ) then result := strpas( buffer )//如果能正确返回错误信息,则转化为Pascal字符串 else//否则返回16进制形式的错误代码 result := 'GetRasError Failure:ErrorID=' + Format( '%x',[ErrorID] ); end; 一、获取当前系统中可用的拨号连接名称   即获取系统中已建立的拨号连接的名称,可用来让用户选择使用哪个拨号连接进行拨号.   可以用两种方法来实现.一种是利用RasAPI函数;另一种是不用RasAPI函数,直接在注册表中查询.   1、不用RasAPI函数,直接在注册表中查询     在注册表的HKEY_USERS.DefaultRemoteAccessAddresses下,列出了已经在拨号网络中建立   了的拨号连接的名称及其属性设置,其中各项目的名称即为可用的拨号连接的名称;各项目的值即   为各拨号连接的属性设置,不过是二进制串,笔者还看不懂.由此可见,我们只要读出各项目的名   称即可获取当前系统中可用的拨号连接名称. var registryTemp : TRegistry; stringsTemp : TStringlist; begin registryTemp := TRegistry.Create; stringsTemp := TStringlist.Create; with registryTemp do begin RootKey := HKEY_USERS;//根键设置为HKEY_USERS //如果存在子键.DefaultRemoteAccessAddresses if OpenKey('.DefaultRemoteAccessAddresses',false) then GetValueNames( stringsTemp );//读出各项目的名称,即拨号连接名称 end; combobox1.Items.assign( stringsTemp );//显示,供选择 end;   2、用RasAPI函数 RasAPI函数RasEnumEntries可获取当前系统中可用的拨号连接名称.其函数原型为 function RasEnumEntries( reserved : PChar;//保留字段,必须为NIL lpszPhonebook : PChar;//电话本名称,在Win9X下无作用,可为空字符串 lprasentryname : LPRASENTRYNAME;//接收拨号连接名称的缓冲区,是一个RASENTRYNAME类型数组的指针 var lpcb : DWORD;//接收拨号连接名称的缓冲区的大小(Bytes) var lpcEntries: DWORD//实际获得的拨号连接名称的数目 ) : DWORD; stdcall; function RasEnumEntries;external RasApiDll name 'RasEnumEntriesA'; 参数lprasentryname提供了一个RASENTRYNAME类型数组的指针,指向一个接收拨号连接名称的缓冲   区,其中RASENTRYNAME及LPRASENTRYNAME的类型说明如下: LPRASENTRYNAME = ^RASENTRYNAME; RASENTRYNAME = record dwSize : DWORD;//该结构所占内存的大小(Bytes),一般设置为SizeOf(RASENTRYNAME) szEntryName : array [ 0..RAS_MaxEntryName ] of char;//拨号连接名称 end;     lpcb为缓冲区的大小,一般设置为dwSize的倍数,倍数为可能有的连接的个数.     lpcEntries实际的连接的个数.     下面是一个应用例子,列出了当前系统中可用的拨号连接名称. 注意,应在RASENTRYNAME缓冲区的第一个RASENTRYNAME结构中设置dwSize. const MaxPhoneEntries = 10;//最多的拨号连接数目 var intIndex : integer; PhoneEntries : array[ 0..MaxPhoneEntries - 1 ] of RASEntryName; dwSize, dwEntries, dwResult : DWORD; begin //在RASENTRYNAME缓冲区的第一个RASENTRYNAME结构中设置dwSize PhoneEntries[ 0 ].dwSize := sizeof( RASEntryName ); dwSize := MaxPhoneEntries * sizeof( RASEntryName );//为缓冲区的大小 //调用RasAPI函数,获取当前系统中可用的拨号连接名称 dwResult := RasEnumEntries ( NIL,'',@PhoneEntries[ 0 ],dwSize, dwEntries ); if dwResult 0 then begin//RasAPI函数,执行错误 memo1.lines.add('RasEnumEntries错误:' + GetRasError( dwResult )); exit; end; //显示当前系统中可用的拨号连接名称 memo1.lines.add('共有' + inttostr( dwEntries ) + '个RAS连接,如下所示'); for intIndex := 0 to dwEntries -1 do memo1.lines.add( strpas( PhoneEntries[ intIndex ].szEntryName ) ); end;   3、获取默认的拨号连接的名称     默认的拨号连接,即用户在浏览器中设置的拨号连接,该连接可以认为是用户最常用   的拨号连接.     在注册表的HKEY_USERS.DefaultRemoteAccess位置,有一个字符串名Profile,它对应   字符值即为HKEY_USERS.DefaultRemoteAccessAddresses. 二、新建拨号连接、修改拨号连接的属性   RasAPI函数RasCreatePhonebookEntry、RasEditPhonebookEntry通过调用Win9X的 新建拨号连接、修改拨号连接的设置界面,允许用户新建拨号连接、修改拨号连接,具体 的设置操作还要由系统来完成.   1、新建拨号连接     新建拨号连接的RasAPI函数为RasCreatePhonebookEntry,其函数原型为: function RasCreatePhonebookEntry( hwnd : THandle; //新建拨号连接窗口的父窗口的句柄,为NIL表示桌面(DeskTop) lpszPhonebook: pchar//电话本名称,在Win9X下无作用,可为空字符串 ) : DWORD;stdcall; function RasCreatePhonebookEntry;external RasApiDll name 'RasCreatePhonebookEntryA';     函数返回值为0表示执行成功;否则为错误代码.     下面是一个应用例子,允许用户新建一个拨号连接. var dwResult : DWORD; begin //在当前窗口中新建拨号连接 dwResult := RasCreatePhonebookEntry( handle, '' ); if dwResult = 0 then memo1.lines.add('新建拨号连接成功!') else memo1.lines.add('新建拨号连接失败:!' + GetRasError( dwResult )) end;   2、修改拨号连接的属性     修改拨号连接的属性的RasAPI函数为RasEditPhonebookEntry,其函数原型为: function RasEditPhonebookEntry( hwnd : THandle; //新建拨号连接窗口的父窗口的句柄,为NIL表示桌面(DeskTop) lpszPhonebook: pchar;//电话本名称,在Win9X下无作用,可为空字符串 lpszEntryName: pchar//拨号连接的名称,如'163'、'169'等 ) : DWORD; stdcall; function RasEditPhonebookEntry;external RasApiDll name 'RasEditPhonebookEntryA';     函数返回值为0表示执行成功;否则为错误代码.     下面是一个应用例子,允许用户修改指定拨号连接的属性. var dwResult : DWORD; begin //在当前窗口中修改拨号连接的属性 dwResult := RasEditPhonebookEntry( handle, '', '163' ); if dwResult = 0 then memo1.lines.add('修改拨号连接成功!') else memo1.lines.add('修改拨号连接失败:!' + GetRasError( dwResult )) end; 三、获取和设置拨号连接的拨号参数   用RasAPI函数RasGetEntryDialParams、RasSetEntryDialParams可以直接获取和设置指定拨号 连接的拨号参数,其中包括用户名称和用户密码!   1、获取拨号连接的拨号参数     获取拨号连接的拨号参数RasAPI函数为RasGetEntryDialParams,其函数原型为: function RasGetEntryDialParams( lpszPhonebook: pchar;//电话本名称,在Win9X下无作用,可为空字符串 pRASDIALPARAMS:LPRASDIALPARAMS;//拨号参数,是一个RASDIALPARAMS类型的指针 var lpfPassword : WordBool//是否需要用户密码 ) : DWORD; stdcall; function RasGetEntryDialParams;external RasApiDll name 'RasGetEntryDialParamsA'; 参数pRASDIALPARAMS是一个RASDIALPARAMS类型的指针,指向一个拨号连接的拨号参数数据 的缓冲区,其中RASDIALPARAMS及LPRASDIALPARAMS的类型说明如下: LPRASDIALPARAMS = ^RASDIALPARAMS; RASDIALPARAMS = record dwSize : DWORD;//该结构所占内存的大小(Bytes),一般设置为SizeOf(RASDIALPARAMS) szEntryName : array[0..RAS_MaxEntryName] of char;//拨号连接名称 szPhoneNumber : array[0..RAS_MaxPhoneNumber] of char;//拨号号码 szCallbackNumber : array[0..RAS_MaxCallbackNumber] of char;//回叫号码 szUserName : array[0..UNLEN] of char;//用户名称 szPassword : array[0..PWLEN] of char;//用户密码 szDomain : array[0..DNLEN] of char;//域名 end;     函数返回值为0表示执行成功;否则为错误代码.     下面是一个应用例子,获取指定拨号连接的拨号参数. var dwResult : DWORD; RASDIALPARAMSData : RASDIALPARAMS; NeedPWD : WordBool; begin //指定拨号连接的名称 with RASDIALPARAMSData do begin dwSize := sizeof( RASDIALPARAMS );//结构大小 szEntryName := '163';//指定拨号连接的名称 szUserName := '';//其它五个参数初始化 szPassword := ''; szDomain := ''; szCallbackNumber := ''; szPhoneNumber := ''; end; NeedPWD := true;//需要用户密码 //获取指定拨号连接的拨号参数 dwResult := RasGetEntryDialParams( '',@RASDIALPARAMSData,NeedPWD ); if dwResult 0 then //获取指定拨号连接的拨号参数失败 memo1.lines.add( '获取'+StrPAS(RASDIALPARAMSData.szEntryName )+'拨号参数失败:' + GetRasError( dwResult )) else begin//显示指定拨号连接的拨号参数 memo1.lines.add( StrPAS(RASDIALPARAMSData.szEntryName )+'拨号参数如下'); memo1.lines.add( '用户名称:' + StrPAS(RASDIALPARAMSData.szUserName )); memo1.lines.add( '用户密码:' + StrPAS(RASDIALPARAMSData.szPassword )); memo1.lines.add( '域 名:' + StrPAS(RASDIALPARAMSData.szDomain )); memo1.lines.add( '回叫号码:' + StrPAS(RASDIALPARAMSData.szCallbackNumber )); memo1.lines.add( '拨号号码:' + StrPAS(RASDIALPARAMSData.szPhoneNumber )); end; end;   2、设置拨号连接的拨号参数     设置拨号连接的拨号参数RasAPI函数为RasSetEntryDialParams,其函数原型为: function RasSetEntryDialParams( lpszPhonebook: pchar;//电话本名称,在Win9X下无作用,可为空字符串 pRASDIALPARAMS:LPRASDIALPARAMS;//拨号参数,是一个RASDIALPARAMS类型的指针 var lpfPassword : WordBool//是否删除用户密码 ) : DWORD; stdcall; function RasSetEntryDialParams;external RasApiDll name 'RasSetEntryDialParamsA'; 参数pRASDIALPARAMS的说明同RasGetEntryDialParams. 参数lpfPassword的含义与RasGetEntryDialParams不同,在此表示是否删除用户密码,为   TRUE时将原来的用户密码删除.          函数返回值为0表示执行成功;否则为错误代码.     下面是一个应用例子,设置指定拨号连接的拨号参数. var dwResult : DWORD; RASDIALPARAMSData : RASDIALPARAMS; RemovePWD : WordBool; begin //指定拨号连接的拨号参数 with RASDIALPARAMSData do begin dwSize := sizeof( RASDIALPARAMS );//结构大小 szEntryName := '163';//指定拨号连接的名称 szUserName := 'MyName';//指定用户名称 szPassword := 'MyPassword';//指定用户密码 szDomain := 'MyDomain';//指定域名 szCallbackNumber := '';//指定回叫号码 szPhoneNumber := '';//指定拨号号码 end; RemovePWD := false;//不需要删除用户密码 //设置指定拨号连接的拨号参数 dwResult := RasSetEntryDialParams( '',@RASDIALPARAMSData,RemovePWD ); if dwResult 0 then //设置指定拨号连接的拨号参数失败 memo1.lines.add( '设置'+StrPAS(RASDIALPARAMSData.szEntryName )+'拨号参数失败:' + GetRasError( dwResult )) else begin//显示指定拨号连接的拨号参数 memo1.lines.add( StrPAS(RASDIALPARAMSData.szEntryName )+'拨号参数设置成功'); memo1.lines.add( '用户名称:' + StrPAS(RASDIALPARAMSData.szUserName )); memo1.lines.add( '用户密码:' + StrPAS(RASDIALPARAMSData.szPassword )); memo1.lines.add( '域 名:' + StrPAS(RASDIALPARAMSData.szDomain )); memo1.lines.add( '回叫号码:' + StrPAS(RASDIALPARAMSData.szCallbackNumber )); memo1.lines.add( '拨号号码:' + StrPAS(RASDIALPARAMSData.szPhoneNumber )); end; end; 四、用指定的拨号连接拨号、挂断指定的拨号连接   1、用指定的拨号连接拨号     拨号有两种方法,一种是调用拨号网络中的拨号程序,就象用户自己用鼠标双击拨号连接名称一   样,用户可以修改拨号号码、用户名称和用户密码,最后由拨号网络来完成拨号过程;另一个方法则   是调用RasAPI函数. (1)用拨号网络中的拨号程序        在程序中可以用如下代码:        winexec('rundll32.exe rnaui.dll,RnaDial 169',SW_SHOWNORMAL);        其中字符串中的最后一个参数“169”为拨号连接的名称。 (2)用RasAPI函数拨号     用拨号连接拨号的RasAPI函数为RasDial,其函数原型为: function RasDial( pRasDialExtensions : LPRASDIALEXTENSIONS;//在WIN9X下无用,可设置为NIL lpszPhonebook : PChar;//电话本名称,在Win9X下无作用,可为空字符串 lpRasDialParams : LPRASDIALPARAMS;//拨号参数 dwNotifierType : DWORD;//消息通知方式 handle : TRasDialFunc;//消息处理事件 var lphRasConn : DWORD//返回的成功连接的连接句柄 ) : DWORD; stdcall; function RasDial;external RasApiDll name 'RasDialA';     参数pRASDIALPARAMS的说明同RasGetEntryDialParams.     参数dwNotifierType表示消息通知方式.在拨号过程中,系统发出拨号事件消息可以通知拨号   进度,因而需要提供接受消息的方式和处理消息的函数.当其值为$FFFFFFFF时,则参数handle被   视为一个窗口的句柄,事件消息被发生该窗口处理;当其值为0时,handle被视为TRasDialFunc类型   的函数的指针;当其值为1时,handle被视为TRasDialFunc1类型的函数的指针.     参数handle表示消息处理函数指针,其类型可以THandle、TRasDialFunc、TRasDialFunc1.当该   参数不为NULL或NIL时,其代表的消息处理函数指针将接受拨号进度通知消息;为NIL时,拨号过程由   异步方式变为同步方式,直到拨号过程成功或失败后RasDial函数才返回.详细可参见Delphi帮助文件   中关于RasDial函数的帮助。     当拨号连接成功时,lphRasConn将表示其连接句柄.     函数返回值为0表示执行成功;否则为错误代码.     下面是一个应用例子,按指定的拨号参数拨号. 看到这的人再顶一顶我接着发... var RASDIALPARAMSData : RASDIALPARAMS; dwResult : DWord; RasCon : DWord; begin //指定拨号连接的拨号参数 with RASDIALPARAMSData do begin dwSize := sizeof( RASDIALPARAMS );//结构大小 szEntryName := '163';//指定拨号连接的名称 szUserName := 'MyName';//指定用户名称 szPassword := 'MyPassword';//指定用户密码 szDomain := 'MyDomain';//指定域名 szCallbackNumber := '';//指定回叫号码 szPhoneNumber := '';//指定拨号号码 end; //用指定的拨号参数拨号,采用同步拨号方式 dwResult := RasDial( NIL,'',@RASDIALPARAMSData,0,NIL,RasCon ); if dwResult 0 then //设置指定拨号连接的拨号参数失败 memo1.lines.add( '用'+StrPAS(RASDIALPARAMSData.szEntryName )+'拨号失败:' + GetRasError( dwResult )) else memo1.lines.add( '用'+StrPAS(RASDIALPARAMSData.szEntryName )+'拨号成功!' ); end;   2、挂断指定的拨号连接     挂断拨号连接的RasAPI函数为RasHangUp,其函数原型为: function RasHangUp( hRasConn : DWORD//要挂断的拨号连接的句柄 ) : DWORD; stdcall; function RasHangUp;external RasApiDll name 'RasHangUpA';     函数返回值为0表示执行成功;否则为错误代码.     下面是一个应用例子,挂断由RasDial建立的拨号连接. //挂断由RasDial建立的拨号连接 dwResult := RasHangUp( RasCon ); if dwResult 0 then //挂断失败 memo1.lines.add( '挂断失败:' + GetRasError( dwResult )) else memo1.lines.add( '挂断成功!'); 五、获取当前活动的连接及其连接状态   1、获取当前活动的连接     获取当前活动的连接的RasAPI函数为RasEnumConnections,其函数原型为: function RasEnumConnections( var lprasconn : RASCONN ;//接收活动连接的缓冲区的指针 var lpcb: DWORD;//缓冲区大小 var lpcConnections : DWORD//实际的活动连接数 ) : DWORD; stdcall; function RasEnumConnections;external RasApiDll name 'RasEnumConnectionsA'; 参数lprasconn提供了一个RASCONN类型数组的指针,指向一个接收活动连接的缓冲   区,其中RASCONN的类型说明如下: RASCONN = record dwSize : DWORD;//该结构所占内存的大小(Bytes),一般设置为SizeOf(RASCONN) hrasconn : HRASCONN;//活动连接的句柄 szEntryName : array[0..RAS_MaxEntryName] of char;//活动连接的名称 szDeviceType : array[0..RAS_MaxDeviceType] of char;//活动连接的所用的设备类型 szDeviceName : array[0..RAS_MaxDeviceName] of char;//活动连接的所用的设备名称 end;     参数lpcb为缓冲区大小(Bytes).     参数lpcConnections将返回实际的连接数目.     函数返回值为0表示执行成功;否则为错误代码.   2、获取指定连接的连接状态     获取指定连接的连接状态的RasAPI函数为RasGetConnectStatus,其函数原型为: function RasGetConnectStatus( hrasconn : HRASCONN; //指定活动连接的句柄 lprasconnstatus : LPRASCONNSTATUS//连接状态参数 ) : DWORD; stdcall; function RasGetConnectStatus;external RasApiDll name 'RasGetConnectStatusA';     连接状态参数lprasconnstatus是一个RASCONNSTATUS类型的指针,将返回连接状态参数.   RASCONNSTATUS和LPRASCONNSTATUS的类型说明如下: LPRASCONNSTATUS = ^RASCONNSTATUS; RASCONNSTATUS = record dwSize : DWORD;//该结构所占内存的大小(Bytes),一般设置为SizeOf(RASCONNSTATUS) rasconnstate : RASCONNSTATE;//连接状态标识,一组DWORD类型数值的集合。 dwError : DWORD;//错误类型标识符 szDeviceType : array[0..RAS_MaxDeviceType] of char;//活动连接的所用的设备类型 szDeviceName : array[0..RAS_MaxDeviceName] of char;//活动连接的所用的设备名称 end;     函数返回值为0表示执行成功;否则为错误代码.     下面是一个应用例子,列出了当前系统中活动的连接的名称及其连接状态. 注意,应在RASCONN缓冲区的第一个RASCONN结构中设置dwSize. const MaxConnections = 10;//最多的拨号连接数目 var connections : array[0..MaxConnections-1] of RASCONN; longSize : dword; intAvailabelConnections : dword; intIndex : integer; dwResult : DWORD; strTemp : string; RASCONNSTATUSData : RASCONNSTATUS; begin connections[ 0 ].dwSize := sizeof(RASCONN);//结构的大小 longSize := MaxConnections * connections[ 0 ].dwSize;//缓冲区大小 intAvailabelConnections := 0;//实际的活动连接的数目 //获取当前系统中活动的连接 dwResult := RasEnumConnections( connections[ 0 ], longSize,intAvailabelConnections ); if dwResult 0 then //获取当前系统中活动的连接 memo1.lines.add( '获取当前系统中活动的连接:' + GetRasError( dwResult )) else begin memo1.lines.add( '当前系统中活动的连接' + inttostr( intAvailabelConnections ) + '个,列举如下' ); for intIndex := 0 to intAvailabelConnections - 1 do begin strTemp := '连接名称:' + StrPAS( connections[ intIndex ].szEntryName ) + ' 设备类型:' + StrPAS( connections[ intIndex ].szDeviceType ) + ' 设备名称:' + StrPAS( connections[ intIndex ].szDeviceName ); //获取连接状态 dwResult := RasGetConnectStatus( connections[ intIndex ].hRasConn,@RASCONNSTATUSData ); if 0 dwResult then strTemp := strTemp + ' 连接状态未知:' + GetRasError( dwResult ) else if RASCONNSTATUSData.rasconnstate = RASCS_Connected then strTemp := strTemp + ' 连接状态:已连接' else strTemp := strTemp + ' 连接状态:(' + inttostr(RASCONNSTATUSData.rasconnstate)+')'; memo1.lines.add( strTemp ); end; end; end;[@more@]

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/36101/viewspace-1030916/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2008-03-17

  • 博文量
    26
  • 访问量
    18869