妈蛋,网上之前看到的没几个是正常的代码。忽悠惨了。度娘搜出来的基本是误人子弟系列。
RasDial(根据字符编辑下属RasDialA(ANSI)和RasDialW(Unicode)两个函数)用于建立Windows到远程计算机的连接。VPN/PPPOE宽带连接都是通过此函数完成连接。
函数原型:
DWORD RasDial( _In_ LPRASDIALEXTENSIONS lpRasDialExtensions, _In_ LPCTSTR lpszPhonebook, _In_ LPRASDIALPARAMS lpRasDialParams, _In_ DWORD dwNotifierType, _In_ LPVOID lpvNotifier, _Out_ LPHRASCONN lphRasConn );
在Ras.h中的定义:
DWORD APIENTRY RasDialA( _In_opt_ LPRASDIALEXTENSIONS, _In_opt_ LPCSTR, _In_ LPRASDIALPARAMSA, _In_ DWORD,
_In_opt_ LPVOID, _Out_ LPHRASCONN );
参数分析
LPRASDIALEXTENSIONS:一个指向RASDIALEXTENSIONS结构体的指针,用于指定拨号操作的一些拓展选项,如果你只进行PPPoE拨号那么这里可以设置为NULL
lpszPhoneBook : 指定电话本的名称,如果你使用Windows默认电话本,请设置此项为NULL
lpRasDialParams :这个是拨号操作的主要配置结构体。包含连接入口(连接的名称,比如“宽带连接”),号码,用户名,密码等等
dwNotifierType:通知类型。PPPoE一般设置为NULL
lpvNotifier:通知时回掉函数的指针。一般设置为NULL,除非你要回掉函数做别的事情。
lphRasConn:连接状态结构体的指针。
建立连接的方式:
首先,你需要判断是否存在一个连接入口(比如我设置我连接的名字叫做“宽带连接”,你要先判断这个链接是否存在,也就是在网络连接中是否能看到你这个连接选项。)
如果入口不存在,调用RasSetEntryProperties函数来建立这个连接入口。这个函数需要一个RASENTRY结构体,这个结构体声明以后第一步是需要用memset函数将结构体数据以0填充避免816错误,并且这个结构体需要设置至少以下内容:
- dwSize : 结构体大小,请通过sizeof(RASENTRY)来获取。
- szLocalPhoneNumber : 一般情况下请设置为空字符串 “”
- szDeviceType:设备类型,根据MSDN的文档,这里请设置为 “RASDT_PPPoE” (PPPOE)
- dwFramingProtocol : 帧结构协议,PPPoE请设置为 RASFP_Ppp (点对点)
- dwType : 类型,请设置为RASET_Broadband (宽带)
- dwfOptions: 连接的选项,这里比较重要,开始因为这里导致了我后面连接建立后却无法通过这个链接上网。这里设置的内容有:RASEO_RemoteDefaultGateway(使用远程默认网关,默认情况请一定设置这个否则无法上网) | RASEO_IpHeaderCompression (IP头压缩,节省一丁点流量) | RASEO_SwCompression (启用软件压缩)
- dwfNetProtocols 连接使用的网络协议,请选择 RASNP_Ip | RASNP_Ipv6 (使用IP和IPV6协议,不设置可能会导致后面调用函数连接出现720错误)
- dwEncryptionType 数据加密,默认ET_Optional(可选加密)
- dwfOptions2 第二选项: RASEO2_Internet (表示此链接指向Internet)
- szDeviceName, 设备名称,我这里是使用了”WAN 微型端口(PPPOE)”这个值
然后调用RasSetEntryProperties(NULL,”你的连接名称”,&RASENTRY结构体,sizeof(RASENTRY结构体),0)建立这个入口
如果入口存在,建立一个RASDIALPARAMS的结构体,并向里面加入必要的数据。然后通过RasDial函数执行链接。
- RASDIALPARAMS需要设置的内容如下实例:szEntryName,szUserName,szPassword,szPhoneNumber
- 其中szUserName是用户名,szPassword是用户密码,szPhoneNumber一般情况下为空字符串,szEntryName是你的连接名称
- 执行 RasDial。
根据连接结果,如果函数返回0表示连接成功,否则连接错误,你可以通过RasGetErrorString获取错误信息
示例代码如下
#define ssRasEntry "ChinaNetSN" DWORD __cdecl example(){ RASENTRYA pRasEntry; if (RasValidateEntryNameA(NULL, ssRasEntry) != ERROR_ALREADY_EXISTS){ memset(&pRasEntry, 0, sizeof(pRasEntry)); pRasEntry.dwSize = sizeof(pRasEntry); pRasEntry.szLocalPhoneNumber[0] = ''; strcpy(pRasEntry.szDeviceType, "RASDT_PPPoE"); pRasEntry.dwFramingProtocol = RASFP_Ppp; pRasEntry.dwType = RASET_Broadband; pRasEntry.dwfOptions = RASEO_SwCompression | RASEO_RemoteDefaultGateway | RASEO_NetworkLogon | RASEO_IpHeaderCompression; pRasEntry.dwfNetProtocols = RASNP_Ip | RASNP_Ipv6 ; pRasEntry.dwEncryptionType = ET_Optional; pRasEntry.dwfOptions2 = RASEO2_Internet; strcpy(pRasEntry.szDeviceName, "WAN 微型端口(PPPOE)"); RasSetEntryPropertiesA(NULL, ssRasEntry, &pRasEntry, sizeof(pRasEntry), NULL, 0); } RASDIALPARAMSA pRasPara; pRasPara.dwSize = sizeof(RASDIALPARAMSA); strcpy(pRasPara.szEntryName, ssRasEntry); strcpy(pRasPara.szCallbackNumber, ""); strcpy(pRasPara.szPhoneNumber, ""); strcpy(pRasPara.szDomain, ""); strcpy(pRasPara.szUserName, pDialUser); strcpy(pRasPara.szPassword, pDialPswd); HRASCONN pHrasCon = NULL; pDialRes = RasDialA(NULL, NULL, &pRasPara, NULL, NULL, &pHrasCon); if (pDialRes != 0) RasHangUpA(pHrasCon); return pDialRes; }