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;

}