创建、连接、挂断、删除VPN实现起来并不难,下面给出一套比较完整的代码。该段代码只是示例代码,但是已经通过了编译,对API的使用和VPN操作步骤是没问题的。具体每个API代表的意义可以参看《C++实现VPN工具之常用API函数》。代码中的OutputString只是起查看消息的作用,当成messagebox理解就行。到此篇总结,VPN工具实现的学习基本上就结束了。

#include "ras.h"
#pragma comment(lib, "rasapi32.lib")

typedef struct VPNPARAMS
{
	WCHAR	szDescription[ RAS_MaxEntryName + 1 ];
	WCHAR	szServer[ RAS_MaxPhoneNumber + 1 ];
	WCHAR	szUserName[ UNLEN + 1 ];
	WCHAR	szPassword[ PWLEN + 1 ];
	WCHAR	szDomain[ DNLEN + 1 ];
	HANDLE	hTerminalEvent;
};

  

#include "stdafx.h"
#include "vpn.h"

RASDIALPARAMS   RasDialParams;
HRASCONN m_hRasConn;
HANDLE g_TerminalEvent;

void OutputString( char *lpFmt, ... )
{
	char buff[1024];
	va_list    arglist;
	va_start( arglist, lpFmt );
	_vsnprintf( buff, sizeof buff, lpFmt, arglist );
	va_end( arglist );
	OutputDebugStringA(buff);
}

inline void InitRASIP (RASIPADDR& rasIP)
{
	rasIP.a =0;
	rasIP.b =0;
	rasIP.c =0;
	rasIP.d =0;
}

//VPN链接过程中返回的步骤信息
void  RasDialFunc(UINT unMsg, RASCONNSTATE rasconnstate, DWORD dwError)
{
	wchar_t szRasString[256]; // Buffer for storing the error string

	if (dwError)  // Error occurred
	{
		RasGetErrorString((UINT)dwError, szRasString, 256);
		OutputString("Error: %d - %s\n",dwError, szRasString);
		SetEvent(g_TerminalEvent);
		return;
	}

	// Map each of the states of RasDial() and display on the screen
	// the next state that RasDial() is entering
	switch (rasconnstate)
	{
		// Running States
	case RASCS_OpenPort:
		OutputString ("Opening port...\n");
		break;
	case RASCS_PortOpened:
		OutputString ("Port opened.\n");
		break;
	case RASCS_ConnectDevice:
		OutputString ("Connecting device...\n");
		break;
	case RASCS_DeviceConnected:
		OutputString ("Device connected.\n");
		break;
	case RASCS_AllDevicesConnected:
		OutputString ("All devices connected.\n");
		break;
	case RASCS_Authenticate:
		OutputString ("Authenticating...\n");
		break;
	case RASCS_AuthNotify:
		OutputString ("Authentication notify.\n");
		break;
	case RASCS_AuthRetry:
		OutputString ("Retrying authentication...\n");
		break;
	case RASCS_AuthCallback:
		OutputString ("Authentication callback...\n");
		break;
	case RASCS_AuthChangePassword:
		OutputString ("Change password...\n");
		break;
	case RASCS_AuthProject:
		OutputString ("Projection phase started...\n");
		break;
	case RASCS_AuthLinkSpeed:
		OutputString ("Negotiating speed...\n");
		break;
	case RASCS_AuthAck:
		OutputString ("Authentication acknowledge...\n");
		break;
	case RASCS_ReAuthenticate:
		OutputString ("Retrying Authentication...\n");
		break;
	case RASCS_Authenticated:
		OutputString ("Authentication complete.\n");
		break;
	case RASCS_PrepareForCallback:
		OutputString ("Preparing for callback...\n");
		break;
	case RASCS_WaitForModemReset:
		OutputString ("Waiting for modem reset...\n");
		break;
	case RASCS_WaitForCallback:
		OutputString ("Waiting for callback...\n");
		break;
	case RASCS_Projected:
		OutputString ("Projection completed.\n");
		break;
#if (WINVER >= 0x400)
	case RASCS_StartAuthentication:
		OutputString ("Starting authentication...\n");
		break;
	case RASCS_CallbackComplete:
		OutputString ("Callback complete.\n");
		break;
	case RASCS_LogonNetwork:
		OutputString ("Logon to the network.\n");
		break;
#endif
	case RASCS_SubEntryConnected:
		OutputString ("Subentry connected.\n");
		break;
	case RASCS_SubEntryDisconnected:
		OutputString ("Subentry disconnected.\n");
		break;

		// The RAS Paused States will not occur because
		// we did not use the RASDIALEXTENSIONS structure
		// to set the RDEOPT_PausedState option flag.

		// The Paused States are:

		// RASCS_RetryAuthentication:
		// RASCS_CallbackSetByCaller:
		// RASCS_PasswordExpired:

		// Terminal States
	case RASCS_Connected:
		OutputString ("Connection completed.\n");
		OutputString ("连接成功\n");
		SetEvent(g_TerminalEvent);
		break;
	case RASCS_Disconnected:
		OutputString ("Disconnecting...\n");
		SetEvent(g_TerminalEvent);
		break;
	default:
		OutputString ("Unknown Status = %d\n", rasconnstate);
		break;
	}
}

//创建一个VPN链接,并保存VPN链接信息到电话薄
BOOL CreateRasEntry(const wchar_t *pszEntryName, const wchar_t *pszServerName, const wchar_t *pszUserName,
					const wchar_t *pszPassWord)
{
	RASENTRY rasEntry;
	DWORD rasEntrySize, dwResult;

	rasEntrySize = sizeof(rasEntry);
	memset(&rasEntry, 0, sizeof(rasEntry));
	DWORD           lpcb    =   0;
	DWORD           lpcDevices;
	RASDEVINFO*     lpRasDevInfo;
	RASDEVINFO      rasdevinfo;

	RasEnumDevices(NULL, &lpcb, &lpcDevices);
	lpRasDevInfo = (LPRASDEVINFO) GlobalAlloc(GPTR, lpcb);
	lpRasDevInfo->dwSize = sizeof(RASDEVINFO);
	//获得所有具有R A S能力的设备名及类型
	RasEnumDevices(lpRasDevInfo, &lpcb, &lpcDevices);
	lstrcpy (rasdevinfo.szDeviceName, lpRasDevInfo->szDeviceName);
	lstrcpy (rasdevinfo.szDeviceType, lpRasDevInfo->szDeviceType);

	rasEntry.dwSize     = sizeof (RASENTRY);
	rasEntry.dwfOptions = RASEO_RequireMsEncryptedPw | RASEO_RequireDataEncryption | RASEO_ModemLights | RASEO_ShowDialingProgress;
	rasEntry.dwAlternateOffset  = 0;
	rasEntry.dwCountryID        = 86;
	rasEntry.dwCountryCode      = 86;
	//  rasEntry.dwDialExtraPercent = 75;
	//  rasEntry.dwDialExtraSampleSeconds = 120;
	//  rasEntry.dwDialMode         = 1;
	rasEntry.dwfNetProtocols = 4;
	//      rasEntry.dwfOptions = 1024262928;
	rasEntry.dwfOptions2 = 367;
	rasEntry.dwFramingProtocol = 1;
	rasEntry.dwHangUpExtraPercent = 10;
	rasEntry.dwHangUpExtraSampleSeconds = 120;
	rasEntry.dwRedialCount = 3;
	rasEntry.dwRedialPause = 60;
	rasEntry.dwType = RASET_Vpn;

	rasEntry.dwFrameSize        = 0;
	rasEntry.dwfNetProtocols    = RASNP_Ip;     // TCP/IP
	rasEntry.dwFramingProtocol  = RASFP_Ppp;    //PPP
	rasEntry.dwChannels         = 0;
	rasEntry.dwReserved1        = 0;
	rasEntry.dwReserved2        = 0;   

	// Strings
	lstrcpy (rasEntry.szAreaCode, L"");
	lstrcpy (rasEntry.szScript, L"");
	lstrcpy (rasEntry.szAutodialDll, L"");
	lstrcpy (rasEntry.szAutodialFunc, L"");
	lstrcpy (rasEntry.szX25PadType, L"");
	lstrcpy (rasEntry.szX25Address, L"");
	lstrcpy (rasEntry.szX25Facilities, L"");
	lstrcpy (rasEntry.szX25UserData, L"");
	//strcpy (rasEntry.szDeviceType, rasdevinfo.szDeviceType );
	//strcpy (rasEntry.szDeviceName, rasdevinfo.szDeviceName);
	//strcpy (rasEntry.szDeviceName,"WAN 微型端口 (L2TP)");
	//strcpy (rasEntry.szDeviceType, "vpn");
	//strcpy (rasEntry.szLocalPhoneNumber,lpszIPAddress);// "60.190.168.108")lstrcpy(rasEntry.szLocalPhoneNumber, pszServerName); ;//服务器地址或域名
	lstrcpy(rasEntry.szDeviceType, RASDT_Vpn);
	lstrcpy(rasEntry.szDeviceName, TEXT("RAS VPN Line 0"));
	rasEntry.dwVpnStrategy = VS_Default;     //vpn类型
	rasEntry.dwEncryptionType = ET_Optional; //数据加密类型   

	// IP addresses
	InitRASIP (rasEntry.ipaddr);
	InitRASIP (rasEntry.ipaddrDns);
	InitRASIP (rasEntry.ipaddrDnsAlt);
	InitRASIP (rasEntry.ipaddrWins);
	InitRASIP (rasEntry.ipaddrWinsAlt);

	dwResult = RasSetEntryProperties(NULL, pszEntryName, &rasEntry, sizeof(rasEntry), NULL, 0);
	if (dwResult != 0)
	{
		OutputString("RasSetEntryProperties %s failed error=%d\n", pszEntryName, dwResult);
		return FALSE;
	}

	RASDIALPARAMS rdParams;
	ZeroMemory(&rdParams, sizeof(RASDIALPARAMS));
	rdParams.dwSize = sizeof(RASDIALPARAMS);
	lstrcpy(rdParams.szEntryName, pszEntryName);
	lstrcpy(rdParams.szUserName, pszUserName);
	lstrcpy(rdParams.szPassword, pszPassWord);
	DWORD dwRet = RasSetEntryDialParams(NULL, &rdParams, FALSE);

	if(dwRet == 0)
		return TRUE;
	else
		return FALSE;
}

//链接一个VPN
BOOL ConenectVPN(LPVOID lparam)
{
	RASCONNSTATUS   RasConnStatus;
	HRASCONN        hRasConn;
	DWORD           Ret;
	DWORD           tcLast;

	VPNPARAMS VPNParams;
	memcpy(&VPNParams, lparam, sizeof(VPNPARAMS));

	// Create the event that indicates a terminal state
	if ((g_TerminalEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
	{
		OutputString("CreateEvent failed with error %d\n", GetLastError());
		return FALSE;
	}

	RasDialParams.dwSize = sizeof(RASDIALPARAMS);

	lstrcpy(RasDialParams.szEntryName, VPNParams.szDescription);
	lstrcpy(RasDialParams.szPhoneNumber, VPNParams.szServer);
	lstrcpy(RasDialParams.szUserName, VPNParams.szUserName);
	lstrcpy(RasDialParams.szPassword, VPNParams.szPassword);
	lstrcpy(RasDialParams.szDomain, VPNParams.szDomain);

	CreateRasEntry(RasDialParams.szEntryName, RasDialParams.szPhoneNumber,
		RasDialParams.szUserName, RasDialParams.szPassword);

	// Dial out asynchronously using RasDial()
	OutputString("Dialing... %s\n", RasDialParams.szPhoneNumber);
	hRasConn = NULL;
	if (Ret = RasDial(NULL, NULL, &RasDialParams, 0, &RasDialFunc, &hRasConn))
	{
		RasDeleteEntry(NULL, RasDialParams.szEntryName);
		return FALSE;
	}
	// Wait for RasDial to complete or enter a paused state
	Ret = WaitForSingleObject(g_TerminalEvent, 50000);

	switch(Ret)
	{
	case WAIT_TIMEOUT:

		// RasDial timed out
		OutputString("RasDial Timed out...\n");

	case WAIT_OBJECT_0:

		// Normal completion or Ras Error encountered
		WaitForSingleObject(VPNParams.hTerminalEvent, INFINITE); // 等待断开
		break;
	}
	OutputString("Calling RasHangUp...\n");
	if (Ret = RasHangUp(hRasConn))
	{
		OutputString("RasHangUp failed with error %d\n", Ret);
		//return FALSE;
	}

	RasConnStatus.dwSize = sizeof(RASCONNSTATUS);

	tcLast = GetTickCount() + 10000;
	while((RasGetConnectStatus(hRasConn, &RasConnStatus)
		!= ERROR_INVALID_HANDLE) && (tcLast > GetTickCount()))
	{
		Sleep(50);
	}

	//RasDeleteEntry(NULL, RasDialParams.szEntryName);
}

//获取VPN的链接状态
bool IsConnect(void)
{
	if(NULL != m_hRasConn)
	{
		RASCONNSTATUS rasConStatus;
		rasConStatus.dwSize = sizeof(RASCONNSTATUS);
		RasGetConnectStatus(m_hRasConn,&rasConStatus);
		if(RASCS_Connected == rasConStatus.rasconnstate)
		{
			return true;
		}
	}
	return false;
}

//挂断VPN链接
bool HangUp()
{
	int index;                 // An integer index
	DWORD dwError,             // Error code from a function call
		dwRasConnSize,       // Size of RasConn in bytes
		dwNumConnections;    // Number of connections found
	RASCONN RasConn[20];       // Buffer for connection state data
	// Assume the maximum number of entries is 20.
	// Assume no more than 20 connections.
	RasConn[0].dwSize = sizeof (RASCONN);
	dwRasConnSize = 20 * sizeof (RASCONN);
	//返回指向VPN数组的指针 Find all connections.
	if (dwError = RasEnumConnections (RasConn, &dwRasConnSize, &dwNumConnections))
	{
		return false;
	}
	// If there are no connections, return zero.
	if (!dwNumConnections)
	{
		return false;
	}
	// Terminate all of the remote access connections.
	for (index = 0; index < (int)dwNumConnections; ++index)
	{
		//这样做主要是不想关掉usb连接,因为通过这种方法得到的连接中包括了USB同步的连接。
		if (wcsstr(RasConn[index].szEntryName,_T("MyLink"))!=NULL)
		{
			if (dwError = RasHangUp (RasConn[index].hrasconn))
			{
				return false;
			}
		}
	}
	return TRUE;
}

//删除建立的VPN拨号
BOOL  DeleteEntry()
{
	RasDeleteEntry(NULL, RasDialParams.szEntryName);
	return TRUE;
}

  

C++实现VPN工具之代码示例的更多相关文章

  1. mysql连接池的使用工具类代码示例

    mysql连接池代码工具示例(scala): import java.sql.{Connection,PreparedStatement,ResultSet} import org.apache.co ...

  2. [转]如何利用ndk-stack工具查看so库的调用堆栈【代码示例】?

    如何利用ndk-stack工具查看so库的调用堆栈[代码示例]? http://hi.baidu.com/subo4110/item/d00395b3bf63e4432bebe36d Step1:An ...

  3. 开发工具类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 六位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数 ...

  4. Python实现各种排序算法的代码示例总结

    Python实现各种排序算法的代码示例总结 作者:Donald Knuth 字体:[增加 减小] 类型:转载 时间:2015-12-11我要评论 这篇文章主要介绍了Python实现各种排序算法的代码示 ...

  5. Java基础知识强化之IO流笔记72:NIO之 NIO核心组件(NIO使用代码示例)

    1.Java NIO 由以下几个核心部分组成: Channels(通道) Buffers(缓冲区) Selectors(选择器) 虽然Java NIO 中除此之外还有很多类和组件,Channel,Bu ...

  6. 转:CodeCube提供可共享、可运行的代码示例

    CodeCube是一个新服务和开源项目,旨在让开发者能够通过浏览器以一种安全的方式分享并运行代码示例从而提升协作. 最初发布的服务可以从codecube.io上获取,支持Ruby.Python.Go及 ...

  7. 天气类API调用的代码示例合集:全国天气预报、实时空气质量数据查询、PM2.5空气质量指数等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 全国天气预报:数据来自国家气象局,可根据地名.经纬度GPS.IP查 ...

  8. 位置信息类API调用的代码示例合集:中国省市区查询、经纬度地址转换、POI检索等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 中国省市区查询:2017最新中国省市区地址 经纬度地址转换:经纬度 ...

  9. 通讯服务类API调用的代码示例合集:短信服务、手机号归属地查询、电信基站查询等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 短信服务:通知类和验证码短信,全国三网合一通道,5秒内到达,费用低 ...

随机推荐

  1. 3步完成chrome切换搜索引擎

    1.打开chrome://settings/,找到搜索 2.点击“管理搜索引擎”,出现弹窗. 增加搜索引擎,三个文本框分别输入:名称.快捷键.地址 3.在新的选项卡中,输入快捷键(如:github), ...

  2. Apache中,同一IP使用多域名对应多个网站的方法

    首先dns中确定有相应的A记录, abc  IN A   211.154.2.5 mail IN A   211.154.2.5 这个讲的是在windows下面配置apache虚拟主机: 一.配置虚拟 ...

  3. 从一个弱引用导致的奔溃 谈 weak assign strong的应用场景【iOS开发教程】

    从一个弱引用导致的奔溃 谈 weak assign strong的应用场景 .h中的定义方法一: @property (nonatomic, assign) NSArray *dataSource; ...

  4. 基于iSCSI的SQL Server 2012群集测试(四)--模拟群集故障转移

    6.模拟群集故障转移 6.1 模拟手动故障转移(1+1) 模拟手动故障转移的目的有以下几点: 测试群集是否能正常故障转移 测试修改端口是否能同步到备节点 测试禁用full-text和Browser服务 ...

  5. jquery 隐藏表单元素

    1.html <label for="lbl" >电压等级:</label> <input class="easyui-combobox&q ...

  6. SRM 513 2 1000CutTheNumbers(状态压缩)

    SRM 513 2 1000CutTheNumbers Problem Statement Manao has a board filled with digits represented as St ...

  7. .NET异步编程之回调

    C#中异步和多线程的区别是什么呢?异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性.甚至有些时候我们就认为异步和多线程是等同的概念.但是,异步和多线程还是有一些区别的.而这些区 ...

  8. [转]看了这个才发现jQuery源代码不是那么晦涩

    很多人觉得jquery.ext等一些开源js源代码 十分的晦涩,读不懂,遇到问题需要调试也很费劲.其实我个人感觉主要是有几个方面的原因: 对一些js不常用的语法.操作符不熟悉 某个function中又 ...

  9. Code First01---CodeFirst项目的搭建

    Entity Framework支持Database First.Model First和Code Only三种开发模式,各模式的开发流程大相径庭,开发体验完全不一样.三种开发模式各有优缺点,对于程序 ...

  10. 在linux下安装Python:

    # 下载最新版本 cd /usr/local/src/ sudo wget http://www.python.org/ftp/python/3.3.2/Python-3.3.2.tar.bz2 su ...