Windows RasDial函数使用

妈蛋,网上之前看到的没几个是正常的代码。忽悠惨了。度娘搜出来的基本是误人子弟系列。 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错误,并且这个结构体需要设置至少以下内容:

  1. dwSize : 结构体大小,请通过sizeof(RASENTRY)来获取。
  2. szLocalPhoneNumber : 一般情况下请设置为空字符串 “”
  3. szDeviceType:设备类型,根据MSDN的文档,这里请设置为 “RASDT_PPPoE” (PPPOE)
  4. dwFramingProtocol : 帧结构协议,PPPoE请设置为 RASFP_Ppp (点对点)
  5. dwType : 类型,请设置为RASET_Broadband (宽带)
  6. dwfOptions: 连接的选项,这里比较重要,开始因为这里导致了我后面连接建立后却无法通过这个链接上网。这里设置的内容有:RASEO_RemoteDefaultGateway(使用远程默认网关,默认情况请一定设置这个否则无法上网) | RASEO_IpHeaderCompression (IP头压缩,节省一丁点流量) | RASEO_SwCompression (启用软件压缩)
  7. dwfNetProtocols 连接使用的网络协议,请选择 RASNP_Ip | RASNP_Ipv6 (使用IP和IPV6协议,不设置可能会导致后面调用函数连接出现720错误)
  8. dwEncryptionType 数据加密,默认ET_Optional(可选加密)
  9. dwfOptions2 第二选项: RASEO2_Internet (表示此链接指向Internet)
  10. szDeviceName, 设备名称,我这里是使用了”WAN 微型端口(PPPOE)”这个值

然后调用RasSetEntryProperties(NULL,”你的连接名称”,&RASENTRY结构体,sizeof(RASENTRY结构体),0)建立这个入口 如果入口存在,建立一个RASDIALPARAMS的结构体,并向里面加入必要的数据。然后通过RasDial函数执行链接。

  1. RASDIALPARAMS需要设置的内容如下实例:szEntryName,szUserName,szPassword,szPhoneNumber
  2. 其中szUserName是用户名,szPassword是用户密码,szPhoneNumber一般情况下为空字符串,szEntryName是你的连接名称
  3. 执行 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;

}