├── src ├── VpnDialerPlus.h ├── VpnDialerPlus.rc ├── res │ ├── VpnDialerPlus.ico │ ├── config.xml │ └── config.xsd ├── packages.config ├── stdafx.cpp ├── AboutDlg.cpp ├── AboutDlg.h ├── VpnDialerPlus.sln ├── VpnDialerPlus.cpp ├── stdafx.h ├── ConfigMgr.h ├── SettingsDlg.h ├── VpnDialerPlus.vcxproj.filters ├── resource.h ├── SettingsDlg.cpp ├── MainDlg.h ├── ConfigMgr.cpp ├── VpnDialerPlus.vcxproj └── MainDlg.cpp ├── .editorconfig ├── img ├── vpndialerplusmain.png └── vpndialerplussettings.png ├── .gitignore ├── license └── readme.md /src/VpnDialerPlus.h: -------------------------------------------------------------------------------- 1 | // VpnDialerPlus.h 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | -------------------------------------------------------------------------------- /src/VpnDialerPlus.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saucecontrol/VpnDialerPlus/HEAD/src/VpnDialerPlus.rc -------------------------------------------------------------------------------- /img/vpndialerplusmain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saucecontrol/VpnDialerPlus/HEAD/img/vpndialerplusmain.png -------------------------------------------------------------------------------- /src/res/VpnDialerPlus.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saucecontrol/VpnDialerPlus/HEAD/src/res/VpnDialerPlus.ico -------------------------------------------------------------------------------- /img/vpndialerplussettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saucecontrol/VpnDialerPlus/HEAD/img/vpndialerplussettings.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | bin 3 | obj 4 | packages 5 | 6 | *.suo 7 | *.obj 8 | *.aps 9 | *.pch 10 | *.ncb 11 | *.sdf 12 | *.user 13 | *.cachefile 14 | -------------------------------------------------------------------------------- /src/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/res/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // VpnDialerPlus.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | -------------------------------------------------------------------------------- /src/AboutDlg.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "resource.h" 3 | 4 | #include "AboutDlg.h" 5 | 6 | LRESULT CAboutDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 7 | { 8 | CenterWindow(GetParent()); 9 | 10 | return TRUE; 11 | } 12 | 13 | LRESULT CAboutDlg::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 14 | { 15 | EndDialog(wID); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/AboutDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CAboutDlg : public CDialogImpl 4 | { 5 | public: 6 | enum { IDD = IDD_ABOUTDLG }; 7 | 8 | BEGIN_MSG_MAP(CAboutDlg) 9 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 10 | COMMAND_ID_HANDLER(IDOK, OnCloseCmd) 11 | COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) 12 | END_MSG_MAP() 13 | 14 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 15 | LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 16 | }; 17 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2005-2017 Clinton Ingram 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/VpnDialerPlus.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VpnDialerPlus", "VpnDialerPlus.vcxproj", "{5F505233-E974-4293-94D2-910A701DC0ED}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5F505233-E974-4293-94D2-910A701DC0ED}.Debug|x64.ActiveCfg = Debug|x64 17 | {5F505233-E974-4293-94D2-910A701DC0ED}.Debug|x64.Build.0 = Debug|x64 18 | {5F505233-E974-4293-94D2-910A701DC0ED}.Debug|x86.ActiveCfg = Debug|Win32 19 | {5F505233-E974-4293-94D2-910A701DC0ED}.Debug|x86.Build.0 = Debug|Win32 20 | {5F505233-E974-4293-94D2-910A701DC0ED}.Release|x64.ActiveCfg = Release|x64 21 | {5F505233-E974-4293-94D2-910A701DC0ED}.Release|x64.Build.0 = Release|x64 22 | {5F505233-E974-4293-94D2-910A701DC0ED}.Release|x86.ActiveCfg = Release|Win32 23 | {5F505233-E974-4293-94D2-910A701DC0ED}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/res/config.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/VpnDialerPlus.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "resource.h" 3 | 4 | #include "MainDlg.h" 5 | 6 | CAppModule _Module; 7 | 8 | int Run(LPWSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT) 9 | { 10 | CMessageLoop theLoop; 11 | _Module.AddMessageLoop(&theLoop); 12 | 13 | CMainDlg dlgMain; 14 | if ( !dlgMain.Create(dlgMain.m_hWnd) ) 15 | { 16 | ATLTRACE(L"Main dialog creation failed!\n"); 17 | return 0; 18 | } 19 | 20 | dlgMain.ShowWindow(nCmdShow); 21 | if ( nCmdShow == SW_SHOWMINIMIZED || nCmdShow == SW_SHOWMINNOACTIVE ) 22 | dlgMain.Minimize(); 23 | 24 | int nRet = theLoop.Run(); 25 | 26 | _Module.RemoveMessageLoop(); 27 | return nRet; 28 | } 29 | 30 | int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ LPWSTR lpstrCmdLine, _In_ int nCmdShow) 31 | { 32 | CMutex mutex(NULL, FALSE, L"Local\\VPNDialer+"); 33 | DWORD dwResult = ::WaitForSingleObjectEx(mutex.m_h, 0, FALSE); 34 | if ( dwResult != WAIT_OBJECT_0 && dwResult != WAIT_ABANDONED ) 35 | { 36 | ::PostMessage(HWND_BROADCAST, WM_VPNDIALERPLUS, 0, 0); 37 | return 0; 38 | } 39 | 40 | ATLENSURE_SUCCEEDED(::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)); 41 | 42 | AtlInitCommonControls(ICC_STANDARD_CLASSES | ICC_BAR_CLASSES | ICC_INTERNET_CLASSES); 43 | 44 | ATLENSURE_SUCCEEDED(_Module.Init(NULL, hInstance)); 45 | 46 | int nRet = Run(lpstrCmdLine, nCmdShow); 47 | 48 | _Module.Term(); 49 | ::CoUninitialize(); 50 | mutex.Release(); 51 | 52 | return nRet; 53 | } 54 | -------------------------------------------------------------------------------- /src/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, 3 | // but are changed infrequently 4 | 5 | #pragma once 6 | 7 | #define WINVER _WIN32_WINNT_WIN6 8 | #define _WIN32_WINNT _WIN32_WINNT_WIN6 9 | #define _WIN32_IE _WIN32_IE_WIN6 10 | #define NTDDI_VERSION NTDDI_WIN6 11 | 12 | #define _ATL_NO_COM 13 | #define _ATL_CSTRING_NO_CRT 14 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS 15 | #define _ATL_CCOMBSTR_EXPLICIT_CONSTRUCTORS 16 | #define _CSTRING_DISABLE_NARROW_WIDE_CONVERSION 17 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 18 | 19 | #include 20 | 21 | #define _S(id) (CString((LPCWSTR)id)) 22 | 23 | #include 24 | 25 | #pragma warning(push) 26 | #pragma warning(disable: ALL_CODE_ANALYSIS_WARNINGS) 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #pragma warning(pop) 33 | 34 | extern CAppModule _Module; 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | 43 | #include 44 | #include 45 | #include 46 | 47 | #pragma warning(push) 48 | #pragma warning(disable: 28301) 49 | #include 50 | #include 51 | #include 52 | #include 53 | #pragma warning(pop) 54 | 55 | #include 56 | 57 | #pragma comment(lib, "rasapi32.lib") 58 | #pragma comment(lib, "rasdlg.lib") 59 | #pragma comment(lib, "iphlpapi.lib") 60 | #pragma comment(lib, "ntdll.lib") 61 | #pragma comment(lib, "ws2_32.lib") 62 | #pragma comment(lib, "credui.lib") 63 | 64 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' processorArchitecture='*' language='*'\"") 65 | -------------------------------------------------------------------------------- /src/ConfigMgr.h: -------------------------------------------------------------------------------- 1 | // ConfigMgr.h : interface of the CConfigMgr class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | 5 | #pragma once 6 | 7 | class CConnection 8 | { 9 | public: 10 | //CConnection() : m_hRasConn(NULL), m_bConnected(false) {} 11 | ~CConnection() {} 12 | 13 | explicit CConnection(const CConnection& conn) 14 | { 15 | sName = conn.sName; 16 | sKeepAlive = conn.sKeepAlive; 17 | asRoutes = conn.asRoutes; 18 | 19 | m_bConnected = conn.m_bConnected; 20 | m_hRasConn = conn.m_hRasConn; 21 | m_evt = const_cast(conn).m_evt; 22 | m_timer = const_cast(conn).m_timer; 23 | } 24 | 25 | explicit CConnection(const CString& name) : sName(name), m_hRasConn(NULL), m_bConnected(false) {} 26 | 27 | CString sName; 28 | CString sKeepAlive; 29 | CSimpleArray asRoutes; 30 | 31 | bool m_bConnected; 32 | HRASCONN m_hRasConn; 33 | CEvent m_evt; 34 | CHandle m_timer; 35 | }; 36 | 37 | typedef CSimpleMap > ConnectionMap; 38 | 39 | class CConfigMgr 40 | { 41 | public: 42 | CConfigMgr() {} 43 | ~CConfigMgr() {} 44 | 45 | bool Init(); 46 | bool ConfigExists(); 47 | bool LoadConfig(bool bCreate = false); 48 | bool LoadConnection(CConnection& conn); 49 | bool SaveConnection(const CConnection& conn); 50 | 51 | CString LastError; 52 | 53 | private: 54 | LPCWSTR CONFIG_FOLDER = L"VPN Dialer+"; 55 | LPCWSTR CONFIG_FILE = L"VpnDialerPlus.config.xml"; 56 | LPCWSTR CONFIG_ELM_CONNECTION = L"Connection"; 57 | LPCWSTR CONFIG_ELM_ADDROUTE = L"AddRoute"; 58 | LPCWSTR CONFIG_ATTR_NAME = L"Name"; 59 | LPCWSTR CONFIG_ATTR_ADDRESS = L"Address"; 60 | LPCWSTR CONFIG_ATTR_MASKBITS = L"MaskBits"; 61 | LPCWSTR CONFIG_ATTR_KEEPALIVE = L"KeepAlive"; 62 | 63 | CComPtr m_pXml; 64 | CComQIPtr m_pElmRoot; 65 | 66 | BSTR GetXPath(LPCWSTR lpszConn); 67 | void SetErrorFromCOM(); 68 | CString m_sPath; 69 | }; 70 | -------------------------------------------------------------------------------- /src/SettingsDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ConfigMgr.h" 4 | 5 | class CSettingsDlg : public CDialogImpl, public CWinDataExchange 6 | { 7 | friend class CMainDlg; 8 | 9 | public: 10 | CSettingsDlg(CConnection& conn) : m_Conn(conn) {} 11 | ~CSettingsDlg() {} 12 | 13 | enum { IDD = IDD_SETTINGSDLG }; 14 | 15 | BEGIN_MSG_MAP(CSettingsDlg) 16 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 17 | COMMAND_HANDLER(IDOK, BN_CLICKED, OnClickedOK) 18 | COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnClickedCancel) 19 | COMMAND_HANDLER(IDC_LIST_ROUTES, LBN_SELCHANGE, OnLbnSelchangeRoutes) 20 | COMMAND_HANDLER(IDC_BUTTON_REMOVE, BN_CLICKED, OnBnClickedRemove) 21 | COMMAND_HANDLER(IDC_BUTTON_ADD, BN_CLICKED, OnBnClickedAdd) 22 | NOTIFY_HANDLER(IDC_IPADDRESS_NET, IPN_FIELDCHANGED, OnIpnFieldchanged) 23 | NOTIFY_HANDLER(IDC_IPADDRESS_MASK, IPN_FIELDCHANGED, OnIpnFieldchanged) 24 | END_MSG_MAP() 25 | 26 | BEGIN_DDX_MAP(CSettingsDlg) 27 | DDX_CONTROL_HANDLE(IDC_IPADDRESS_NET, m_ipNet) 28 | DDX_CONTROL_HANDLE(IDC_IPADDRESS_MASK, m_ipMask) 29 | DDX_CONTROL_HANDLE(IDC_IPADDRESS_KEEPALIVE, m_ipKeepAlive) 30 | DDX_CONTROL_HANDLE(IDC_LIST_ROUTES, m_lstRoutes) 31 | DDX_CONTROL_HANDLE(IDC_BUTTON_ADD, m_btnAdd) 32 | DDX_CONTROL_HANDLE(IDC_BUTTON_REMOVE, m_btnRemove) 33 | END_DDX_MAP() 34 | 35 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 36 | LRESULT OnClickedOK(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 37 | LRESULT OnClickedCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 38 | LRESULT OnLbnSelchangeRoutes(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 39 | LRESULT OnIpnFieldchanged(int /*idCtrl*/, LPNMHDR /*pNMHDR*/, BOOL& /*bHandled*/); 40 | LRESULT OnBnClickedRemove(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 41 | LRESULT OnBnClickedAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 42 | 43 | private: 44 | CConnection& m_Conn; 45 | 46 | CIPAddressCtrl m_ipNet; 47 | CIPAddressCtrl m_ipMask; 48 | CIPAddressCtrl m_ipKeepAlive; 49 | CListBox m_lstRoutes; 50 | CButton m_btnAdd; 51 | CButton m_btnRemove; 52 | }; 53 | -------------------------------------------------------------------------------- /src/VpnDialerPlus.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {94feb9fb-77e7-4894-9968-bf16aebf6c78} 6 | cpp;c;cxx;def;odl;idl;hpj;bat;asm 7 | 8 | 9 | {7aae26da-1bc4-47f5-af69-b1ebb80c5c2e} 10 | h;hpp;hxx;hm;inl;inc 11 | 12 | 13 | {c8b68322-262b-4cc3-8136-33164067a7ee} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | 58 | 59 | Resource Files 60 | 61 | 62 | 63 | 64 | Resource Files 65 | 66 | 67 | 68 | 69 | Resource Files 70 | 71 | 72 | 73 | 74 | Resource Files 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by VpnDialerPlus.rc 4 | // 5 | #define IDD_MAINDLG 100 6 | #define IDD_SETTINGSDLG 101 7 | #define IDD_ABOUTDLG 102 8 | #define IDR_ICON_MAIN 200 9 | #define IDS_ERR_MSXML6 201 10 | #define IDS_ERR_COM 202 11 | #define IDS_ERR_RASENUMENTRIES 203 12 | #define IDS_ERR_RASENTRYDLG 204 13 | #define IDS_ERR_RASGETENTRYPROPERTIES 205 14 | #define IDS_ERR_RASENUMCONNECTIONS 206 15 | #define IDS_ERR_RASDIALGETENTRYDIALPARAMS 207 16 | #define IDS_ERR_RASDIAL 208 17 | #define IDS_ERR_RASCONNECTIONNOTIFICATION 209 18 | #define IDS_ERR_RASGETPROJECTIONINFO 210 19 | #define IDS_ERR_GETIPFORWARDTABLE 211 20 | #define IDS_ERR_CREATEIPFORWARDENTRY 212 21 | #define IDS_ERR_DELETEIPFORWARDENTRY 213 22 | #define IDS_ERR_CONFIGURATION 214 23 | #define IDS_ERR_UNKNOWN 215 24 | #define IDS_ERR_INVALIDCONFIG 216 25 | #define IDS_MSG_NEWCONFIG 217 26 | #define IDS_FMT_ERRORCODE 218 27 | #define IDS_FMT_LOGONTITLE 219 28 | #define IDS_FMT_SETTINGSTITLE 220 29 | #define IDS_STATUS_OPENINGPORT 221 30 | #define IDS_STATUS_CONNECTING 222 31 | #define IDS_STATUS_AUTHENTICATING 223 32 | #define IDS_STATUS_PROJECTING 224 33 | #define IDS_STATUS_ADDINGROUTES 225 34 | #define IDS_STATUS_CONNECTED 226 35 | #define IDS_STATUS_DISCONNECTED 227 36 | #define IDS_NIF_TIP 228 37 | #define IDS_LBL_EMPTYLIST 229 38 | #define IDS_MSG_NOELIGIBLEROUTE 230 39 | #define IDS_MSG_CREDENTIALS 231 40 | #define IDR_MENU_POPUP 300 41 | #define IDC_COMBO_CONNECTIONS 1000 42 | #define IDC_STATIC_STATUS 1001 43 | #define IDC_BUTTON_CONNECT 1002 44 | #define IDC_BUTTON_DISCONNECT 1003 45 | #define IDC_BUTTON_SETTINGS 1004 46 | #define IDC_BUTTON_PROPERTIES 1005 47 | #define IDC_BUTTON_NEW 1006 48 | #define IDC_IPADDRESS_NET 1007 49 | #define IDC_IPADDRESS_MASK 1008 50 | #define IDC_LIST_ROUTES 1009 51 | #define IDC_BUTTON_ADD 1010 52 | #define IDC_BUTTON_REMOVE 1011 53 | #define IDC_IPADDRESS_KEEPALIVE 1012 54 | #define IDC_EDIT_USER 1013 55 | #define IDC_EDIT_PASS 1014 56 | #define ID_CONNECT 32772 57 | #define ID_DISCONNECT 32773 58 | 59 | // Next default values for new objects 60 | // 61 | #ifdef APSTUDIO_INVOKED 62 | #ifndef APSTUDIO_READONLY_SYMBOLS 63 | #define _APS_NO_MFC 1 64 | #define _APS_NEXT_RESOURCE_VALUE 301 65 | #define _APS_NEXT_COMMAND_VALUE 32774 66 | #define _APS_NEXT_CONTROL_VALUE 1015 67 | #define _APS_NEXT_SYMED_VALUE 103 68 | #endif 69 | #endif 70 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | VPN Dialer+ 2 | =========== 3 | 4 | VPN Dialer+ is a lightweight utility that works with the Windows VPN Client to enable easy management of [split-tunnel](https://en.wikipedia.org/wiki/Split_tunneling) configurations. 5 | 6 | Under most configurations, when you connect to a VPN, all traffic is sent over the VPN, whether it needs to be or not. 7 | 8 | With split tunneling, you can connect to a VPN and route only traffic that is destined for specific IP addresses or ranges over the VPN, while using your local Internet connection directly for all other traffic. This type of configuration has several benefits: 9 | 10 | * You can connect to multiple VPNs at the same time and have traffic routed appropriately for each one. 11 | * Your non-VPN traffic will move at the speed of your local Internet connection, not the speed of the VPN. 12 | * Your non-VPN traffic is not subject to any filtering or snooping that might be in place on the VPN network. 13 | 14 | App Features 15 | ------------ 16 | 17 | * Automatically monitor VPN connection status and apply routing updates when the VPN is connected/disconnected. 18 | * Prevent idle disconnection by sending periodic ICMP packets to a target over the VPN. 19 | * Compact program with low memory footprint so you can leave it running at all times. 20 | * Minimizes to the System Tray to keep out of your way. 21 | 22 | Requirements 23 | ------------ 24 | 25 | Windows Vista or later. You must have admin permissions to modify the routing table. 26 | 27 | Installation 28 | ------------ 29 | 30 | VPN Dialer+ is a portable .exe with zero external dependencies. Configuration is stored in the AppData folder. 31 | 32 | Binaries for x86 and x64 Windows are available on the [releases page](https://github.com/saucecontrol/VpnDialerPlus/releases). 33 | 34 | Usage 35 | ----- 36 | 37 | ![main dialog](img/vpndialerplusmain.png "VPN Dialer+ Main Dialog") 38 | 39 | The main dialog is simple, with a dropdown list of VPN connections and four buttons 40 | 41 | ### New 42 | 43 | Create a new VPN connection. This button simply launches the Windows New VPN Connection dialog. 44 | 45 | ### Properties 46 | 47 | Change VPN connection properties. This button simply launches the Windows VPN Connection Properties dialog. 48 | 49 | ### Connect 50 | 51 | Connect the selected VPN and add your custom routes. If your connection does not have your authentication information saved, you will be prompted for credentials. 52 | 53 | ### Settings 54 | 55 | Launches the VPN Dialer+ Settings dialog for the selected connection. 56 | 57 | ![settings dialog](img/vpndialerplussettings.png "VPN Dialer+ Settings Dialog") 58 | 59 | ### Static Routes 60 | 61 | Add IP address and subnet mask information for any custom routes you would like for this connection. Your routes will replace the default route from the connection. 62 | 63 | The routes you configure may have a subnet mask of any length. A subnet mask of 0.0.0.0 will route all traffic through the VPN. A subnet mask of 255.255.255.255 will route traffic to only a single IP address through the VPN. You may enter multiple routes to networks and/or hosts. 64 | 65 | ### Connection Keep-Alive 66 | 67 | If the VPN to which you are connecting has an idle timeout configured, you may be able to prevent being detected as idle by sending an ICMP echo packet over the connection periodically. 68 | 69 | Enter an IP address of a server or other host that is likely to be always on, and VPN Dialer+ will ping it every 6 seconds to keep your connection active. 70 | -------------------------------------------------------------------------------- /src/SettingsDlg.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "resource.h" 3 | 4 | #include "SettingsDlg.h" 5 | 6 | LRESULT CSettingsDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 7 | { 8 | CString sTitle; 9 | sTitle.Format(IDS_FMT_SETTINGSTITLE, m_Conn.sName.GetString()); 10 | SetWindowText(sTitle); 11 | 12 | CenterWindow(GetParent()); 13 | DoDataExchange(DDX_LOAD); 14 | 15 | for ( int i = 0; i < m_Conn.asRoutes.GetSize(); i++ ) 16 | { 17 | m_lstRoutes.AddString(m_Conn.asRoutes[i]); 18 | } 19 | 20 | if ( !m_Conn.sKeepAlive.IsEmpty() ) 21 | { 22 | IPAddr ulKeepAlive = ::inet_addr(CW2A(m_Conn.sKeepAlive)); 23 | m_ipKeepAlive.SetAddress(::ntohl(ulKeepAlive)); 24 | } 25 | 26 | return TRUE; 27 | } 28 | 29 | LRESULT CSettingsDlg::OnClickedOK(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 30 | { 31 | m_Conn.asRoutes.RemoveAll(); 32 | for ( int i = 0; i < m_lstRoutes.GetCount(); i++ ) 33 | { 34 | CString sItem; 35 | m_lstRoutes.GetText(i, sItem); 36 | m_Conn.asRoutes.Add(sItem); 37 | } 38 | 39 | IPAddr ulKeepAlive; 40 | m_ipKeepAlive.GetAddress(&ulKeepAlive); 41 | 42 | m_Conn.sKeepAlive.Empty(); 43 | if ( ulKeepAlive != 0 ) 44 | { 45 | IN_ADDR iaKeepAlive; 46 | iaKeepAlive.s_addr = ::htonl(ulKeepAlive); 47 | 48 | m_Conn.sKeepAlive = CA2W(::inet_ntoa(iaKeepAlive)); 49 | } 50 | 51 | DoDataExchange(DDX_SAVE); 52 | EndDialog(TRUE); 53 | 54 | return 0; 55 | } 56 | 57 | LRESULT CSettingsDlg::OnClickedCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 58 | { 59 | EndDialog(FALSE); 60 | 61 | return 0; 62 | } 63 | 64 | LRESULT CSettingsDlg::OnLbnSelchangeRoutes(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 65 | { 66 | m_btnRemove.EnableWindow(); 67 | 68 | return 0; 69 | } 70 | 71 | LRESULT CSettingsDlg::OnIpnFieldchanged(int /*idCtrl*/, LPNMHDR /*pNMHDR*/, BOOL& /*bHandled*/) 72 | { 73 | if ( m_ipNet.IsBlank() || m_ipMask.IsBlank() ) 74 | m_btnAdd.EnableWindow(FALSE); 75 | else 76 | m_btnAdd.EnableWindow(); 77 | 78 | return 0; 79 | } 80 | 81 | LRESULT CSettingsDlg::OnBnClickedAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 82 | { 83 | m_btnAdd.EnableWindow(FALSE); 84 | 85 | IPAddr ulNet, ulMask, ulMaskT; 86 | m_ipNet.GetAddress(&ulNet); 87 | m_ipMask.GetAddress(&ulMaskT); 88 | 89 | ulMask = 0; 90 | while ( (ulMaskT & 0x80000000UL) == 0x80000000UL ) 91 | { 92 | ulMask = ulMask >> 1 | 0x80000000UL; 93 | ulMaskT <<= 1; 94 | } 95 | ulNet &= ulMask; 96 | 97 | IN_ADDR iaNet, iaMask; 98 | iaNet.s_addr = ::htonl(ulNet); 99 | ::ConvertIpv4MaskToLength(::htonl(ulMask), &iaMask.s_net); 100 | 101 | CString sRoute; 102 | sRoute.Format(L"%s/%d", CA2W(::inet_ntoa(iaNet)).m_psz, static_cast(iaMask.s_net)); 103 | m_lstRoutes.AddString(sRoute); 104 | 105 | m_ipNet.ClearAddress(); 106 | m_ipMask.ClearAddress(); 107 | 108 | return 0; 109 | } 110 | 111 | LRESULT CSettingsDlg::OnBnClickedRemove(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 112 | { 113 | m_btnRemove.EnableWindow(FALSE); 114 | m_btnAdd.EnableWindow(); 115 | 116 | CString sSel; 117 | m_lstRoutes.GetText(m_lstRoutes.GetCurSel(), sSel); 118 | 119 | IN_ADDR iaNet, iaMask; 120 | LPCWSTR szRoute = sSel; 121 | ::RtlIpv4StringToAddress(szRoute, TRUE, &szRoute, &iaNet); 122 | ::ConvertLengthToIpv4Mask(::StrToInt(szRoute + 1), &iaMask.s_addr); 123 | 124 | m_ipNet.SetAddress(::ntohl(iaNet.s_addr)); 125 | m_ipMask.SetAddress(::ntohl(iaMask.s_addr)); 126 | 127 | m_lstRoutes.DeleteString(m_lstRoutes.GetCurSel()); 128 | 129 | return 0; 130 | } -------------------------------------------------------------------------------- /src/MainDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ConfigMgr.h" 4 | 5 | const UINT WM_VPNDIALERPLUS = ::RegisterWindowMessage(L"VPN Dialer+ Restore"); 6 | const UINT WM_TASKBARCREATED = ::RegisterWindowMessage(L"TaskbarCreated"); 7 | 8 | class CMainDlg : public CDialogImpl, public CUpdateUI, public CMessageFilter, 9 | public CIdleHandler, public CWinDataExchange, public IWorkerThreadClient 10 | { 11 | friend class CLogonDlg; 12 | friend class CSettingsDlg; 13 | 14 | public: 15 | CMainDlg() : m_bDblClick(false) {} 16 | ~CMainDlg() {} 17 | 18 | enum { IDD = IDD_MAINDLG }; 19 | 20 | virtual BOOL PreTranslateMessage(MSG* pMsg); 21 | virtual BOOL OnIdle(); 22 | 23 | BEGIN_UPDATE_UI_MAP(CMainDlg) 24 | END_UPDATE_UI_MAP() 25 | 26 | BEGIN_MSG_MAP(CMainDlg) 27 | MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) 28 | MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) 29 | MESSAGE_HANDLER(WM_USER, OnUser) 30 | MESSAGE_HANDLER(WM_MENUCOMMAND, OnMenuCommand) 31 | MESSAGE_HANDLER(WM_VPNDIALERPLUS, OnRestore) 32 | MESSAGE_HANDLER(WM_TASKBARCREATED, OnTaskbarCreated) 33 | COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout) 34 | COMMAND_ID_HANDLER(IDCANCEL, OnCancel) 35 | COMMAND_ID_HANDLER(ID_FILE_OPEN, OnMenuOpen) 36 | COMMAND_HANDLER(IDC_BUTTON_CONNECT, BN_CLICKED, OnBnClickedConnect) 37 | COMMAND_HANDLER(IDC_BUTTON_DISCONNECT, BN_CLICKED, OnBnClickedDisconnect) 38 | COMMAND_HANDLER(IDC_BUTTON_PROPERTIES, BN_CLICKED, OnBnClickedProperties) 39 | COMMAND_HANDLER(IDC_BUTTON_SETTINGS, BN_CLICKED, OnBnClickedSettings) 40 | COMMAND_HANDLER(IDC_BUTTON_NEW, BN_CLICKED, OnBnClickedNew) 41 | COMMAND_HANDLER(IDC_COMBO_CONNECTIONS, CBN_SELCHANGE, OnCbnSelchangeConnections) 42 | END_MSG_MAP() 43 | 44 | BEGIN_DDX_MAP(CMainDlg) 45 | DDX_CONTROL_HANDLE(IDC_BUTTON_CONNECT, m_btnConnect); 46 | DDX_CONTROL_HANDLE(IDC_BUTTON_DISCONNECT, m_btnDisconnect); 47 | DDX_CONTROL_HANDLE(IDC_BUTTON_PROPERTIES, m_btnProperties); 48 | DDX_CONTROL_HANDLE(IDC_BUTTON_SETTINGS, m_btnSettings); 49 | DDX_CONTROL_HANDLE(IDC_BUTTON_NEW, m_btnNew); 50 | DDX_CONTROL_HANDLE(IDC_COMBO_CONNECTIONS, m_cboConnections); 51 | DDX_CONTROL_HANDLE(IDC_STATIC_STATUS, m_stcStatus); 52 | END_DDX_MAP() 53 | 54 | LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 55 | LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 56 | LRESULT OnUser(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 57 | LRESULT OnMenuCommand(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 58 | LRESULT OnRestore(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 59 | LRESULT OnTaskbarCreated(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); 60 | LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 61 | LRESULT OnCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 62 | LRESULT OnMenuOpen(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 63 | LRESULT OnBnClickedConnect(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 64 | LRESULT OnBnClickedDisconnect(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 65 | LRESULT OnBnClickedSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 66 | LRESULT OnBnClickedProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 67 | LRESULT OnBnClickedNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 68 | LRESULT OnCbnSelchangeConnections(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); 69 | 70 | void CloseDialog(int nVal); 71 | 72 | bool IsVpnConnection(LPCWSTR pszEntryName); 73 | void PopulateVPNList(); 74 | void UpdateConnections(); 75 | void UpdateUI(); 76 | void Connect(CConnection& conn); 77 | void Disconnect(CConnection& conn); 78 | void PostConnect(CConnection& conn); 79 | void RasDialog(const CString& sConnName); 80 | void Minimize(); 81 | void NotifyIcon(bool bShow); 82 | void CreateMenu(); 83 | int ReportError(LPCWSTR szErr, UINT_PTR nRes, UINT nType = MB_OK | MB_ICONERROR); 84 | static CString GetErrorString(DWORD dwErr); 85 | 86 | // RasDialFunc2 87 | static void CALLBACK RasDialCallback(ULONG_PTR dwCallbackId, DWORD dwSubEntry, HRASCONN hRasConn, UINT unMsg, RASCONNSTATE RasConnState, DWORD dwError, DWORD dwExtendedError); 88 | 89 | // IWorkerThreadClient 90 | HRESULT Execute(DWORD_PTR dwParam, HANDLE hObject); 91 | HRESULT CloseHandle(HANDLE hObject); 92 | 93 | private: 94 | LPCWSTR EMPTY_STRING = L""; 95 | 96 | CWorkerThread m_threadConNotify; 97 | CWorkerThread m_threadDisNotify; 98 | CWorkerThread m_threadKeepAlive; 99 | 100 | CString m_sSelectedConnection; 101 | ConnectionMap m_ConnMap; 102 | 103 | CButton m_btnConnect; 104 | CButton m_btnDisconnect; 105 | CButton m_btnProperties; 106 | CButton m_btnSettings; 107 | CButton m_btnNew; 108 | CComboBox m_cboConnections; 109 | CStatic m_stcStatus; 110 | CEvent m_evt; 111 | 112 | CMenu m_menu; 113 | bool m_bDblClick; 114 | }; 115 | -------------------------------------------------------------------------------- /src/ConfigMgr.cpp: -------------------------------------------------------------------------------- 1 | // ConfigMgr.cpp : implementation of the CConfigMgr class 2 | // 3 | ///////////////////////////////////////////////////////////////////////////// 4 | 5 | #include "stdafx.h" 6 | #include "resource.h" 7 | 8 | #include "ConfigMgr.h" 9 | 10 | bool CConfigMgr::Init() 11 | { 12 | if ( m_pXml ) 13 | return true; 14 | 15 | HRESULT hr = m_pXml.CoCreateInstance(__uuidof(DOMDocument60)); 16 | if ( FAILED(hr) ) 17 | return !LastError.LoadString(IDS_ERR_MSXML6); 18 | 19 | CComPtr pXsd; 20 | CComPtr pSC; 21 | ATLENSURE_SUCCEEDED(pXsd.CoCreateInstance(__uuidof(DOMDocument60))); 22 | ATLENSURE_SUCCEEDED(pSC.CoCreateInstance(__uuidof(XMLSchemaCache60))); 23 | 24 | CComBSTR sProp(L"NewParser"); 25 | CComVariant vVal(true); 26 | m_pXml->setProperty(sProp, vVal); 27 | pXsd->setProperty(sProp, vVal); 28 | 29 | CResource res; 30 | res.Load(L"XML", L"config.xsd"); 31 | CComBSTR xsd(res.GetSize(), static_cast(res.Lock())); 32 | 33 | VARIANT_BOOL bS = VARIANT_FALSE; 34 | ATLENSURE(SUCCEEDED(pXsd->loadXML(xsd, &bS)) && bS); 35 | ATLENSURE_SUCCEEDED(pSC->add(NULL, CComVariant(pXsd))); 36 | ATLENSURE_SUCCEEDED(m_pXml->putref_schemas(CComVariant(pSC))); 37 | 38 | LPWSTR pwszPath = m_sPath.GetBuffer(MAX_PATH + 1); 39 | ::SHGetFolderPathAndSubDir(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, CONFIG_FOLDER, pwszPath); 40 | ::PathAppend(pwszPath, CONFIG_FILE); 41 | m_sPath.ReleaseBuffer(); 42 | 43 | return true; 44 | } 45 | 46 | bool CConfigMgr::ConfigExists() 47 | { 48 | return ::PathFileExists(m_sPath); 49 | } 50 | 51 | bool CConfigMgr::LoadConfig(bool bCreate) 52 | { 53 | ATLASSERT(m_pXml); 54 | if ( m_pElmRoot ) 55 | return true; 56 | 57 | LastError.Empty(); 58 | 59 | VARIANT_BOOL bS = VARIANT_FALSE; 60 | HRESULT hr = m_pXml->load(CComVariant(m_sPath), &bS); 61 | if ( (FAILED(hr) || !bS) && bCreate ) 62 | { 63 | CResource res; 64 | res.Load(L"XML", L"config.xml"); 65 | CComBSTR xml(res.GetSize(), static_cast(res.Lock())); 66 | 67 | ATLENSURE(SUCCEEDED(m_pXml->loadXML(xml, &bS)) && bS); 68 | 69 | hr = m_pXml->save(CComVariant(m_sPath)); 70 | } 71 | 72 | if ( SUCCEEDED(hr) && bS ) 73 | { 74 | m_pXml->get_documentElement(&m_pElmRoot); 75 | return true; 76 | } 77 | 78 | SetErrorFromCOM(); 79 | return false; 80 | } 81 | 82 | bool CConfigMgr::LoadConnection(CConnection& conn) 83 | { 84 | ATLASSERT(m_pElmRoot); 85 | 86 | CComBSTR bstrXPath; 87 | bstrXPath.Attach(GetXPath(conn.sName)); 88 | 89 | CComPtr pNode; 90 | HRESULT hr = m_pElmRoot->selectSingleNode(bstrXPath, &pNode); 91 | if ( FAILED(hr) || !pNode ) 92 | return false; 93 | 94 | CComQIPtr pElm(pNode); 95 | CComVariant vt; 96 | 97 | pElm->getAttribute(CComBSTR(CONFIG_ATTR_KEEPALIVE), &vt); 98 | conn.sKeepAlive = vt.bstrVal; 99 | vt.Clear(); 100 | 101 | CComPtr pNL; 102 | pElm->get_childNodes(&pNL); 103 | 104 | long lLen = 0; 105 | pNL->get_length(&lLen); 106 | 107 | for ( long i = 0; i < lLen; i++ ) 108 | { 109 | pNode.Release(); 110 | pNL->get_item(i, &pNode); 111 | 112 | CString sRoute; 113 | CComQIPtr pElmRoute(pNode); 114 | 115 | pElmRoute->getAttribute(CComBSTR(CONFIG_ATTR_ADDRESS), &vt); 116 | sRoute = vt.bstrVal; 117 | vt.Clear(); 118 | 119 | sRoute.AppendChar(L'/'); 120 | 121 | pElmRoute->getAttribute(CComBSTR(CONFIG_ATTR_MASKBITS), &vt); 122 | sRoute.Append(vt.bstrVal); 123 | vt.Clear(); 124 | 125 | conn.asRoutes.Add(sRoute); 126 | } 127 | 128 | return true; 129 | } 130 | 131 | bool CConfigMgr::SaveConnection(const CConnection &conn) 132 | { 133 | ATLASSERT(m_pElmRoot); 134 | 135 | CComBSTR bstrXPath; 136 | bstrXPath.Attach(GetXPath(conn.sName)); 137 | 138 | CComPtr pNode; 139 | HRESULT hr = m_pElmRoot->selectSingleNode(bstrXPath, &pNode); 140 | if ( FAILED(hr) || !pNode ) 141 | { 142 | CComPtr pElmNew; 143 | m_pXml->createElement(CComBSTR(CONFIG_ELM_CONNECTION), &pElmNew); 144 | pElmNew->setAttribute(CComBSTR(CONFIG_ATTR_NAME), CComVariant(conn.sName)); 145 | 146 | pNode = pElmNew; 147 | 148 | CComPtr pNodeNew; 149 | m_pElmRoot->appendChild(pNode, &pNodeNew); 150 | } 151 | 152 | CComQIPtr pElm(pNode); 153 | if ( !conn.sKeepAlive.IsEmpty() ) 154 | pElm->setAttribute(CComBSTR(CONFIG_ATTR_KEEPALIVE), CComVariant(conn.sKeepAlive)); 155 | else 156 | pElm->removeAttribute(CComBSTR(CONFIG_ATTR_KEEPALIVE)); 157 | 158 | pNode.Release(); 159 | while ( SUCCEEDED(pElm->get_lastChild(&pNode)) && pNode ) 160 | { 161 | CComPtr pNodeOld; 162 | pElm->removeChild(pNode, &pNodeOld); 163 | pNode.Release(); 164 | } 165 | 166 | for ( int i = 0; i < conn.asRoutes.GetSize(); i++ ) 167 | { 168 | int slashPos = conn.asRoutes[i].Find(L'/'); 169 | CComBSTR sNet = conn.asRoutes[i].Left(slashPos); 170 | CComBSTR sMask = conn.asRoutes[i].Mid(slashPos + 1); 171 | 172 | CComPtr pElmNew; 173 | m_pXml->createElement(CComBSTR(CONFIG_ELM_ADDROUTE), &pElmNew); 174 | pElmNew->setAttribute(CComBSTR(CONFIG_ATTR_ADDRESS), CComVariant(sNet)); 175 | pElmNew->setAttribute(CComBSTR(CONFIG_ATTR_MASKBITS), CComVariant(sMask)); 176 | 177 | pNode = pElmNew; 178 | 179 | CComPtr pNodeNew; 180 | pElm->appendChild(pNode, &pNodeNew); 181 | } 182 | 183 | hr = m_pXml->save(CComVariant(m_sPath)); 184 | if ( FAILED(hr) ) 185 | { 186 | SetErrorFromCOM(); 187 | return false; 188 | } 189 | 190 | return true; 191 | } 192 | 193 | BSTR CConfigMgr::GetXPath(LPCWSTR lpszConn) 194 | { 195 | CComBSTR bstrXPath(CONFIG_ELM_CONNECTION); 196 | bstrXPath += L"[@"; 197 | bstrXPath += CONFIG_ATTR_NAME; 198 | bstrXPath += L"='"; 199 | bstrXPath += lpszConn; 200 | bstrXPath += L"']"; 201 | 202 | return bstrXPath.Detach(); 203 | } 204 | 205 | void CConfigMgr::SetErrorFromCOM() 206 | { 207 | CComPtr pErr; 208 | 209 | HRESULT hr = ::GetErrorInfo(0, &pErr); 210 | if ( SUCCEEDED(hr) ) 211 | { 212 | CComBSTR bstrErr; 213 | pErr->GetDescription(&bstrErr); 214 | LastError = bstrErr; 215 | } 216 | else 217 | ATLENSURE(LastError.LoadString(IDS_ERR_COM)); 218 | } 219 | -------------------------------------------------------------------------------- /src/VpnDialerPlus.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {5F505233-E974-4293-94D2-910A701DC0ED} 23 | VpnDialerPlus 24 | 10.0 25 | 26 | 27 | 28 | Application 29 | v142 30 | true 31 | Static 32 | Unicode 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | <_ProjectFileVersion>15.0.26419.1 45 | 46 | 47 | NativeRecommendedRules.ruleset 48 | true 49 | 50 | 51 | bin\x86\$(Configuration)\ 52 | bin\x86\$(Configuration)\ 53 | 54 | 55 | bin\$(Platform)\$(Configuration)\ 56 | bin\$(Platform)\$(Configuration)\ 57 | 58 | 59 | 60 | false 61 | Use 62 | true 63 | Level3 64 | Fast 65 | true 66 | 67 | 68 | 0x0409 69 | $(IntDir);%(AdditionalIncludeDirectories) 70 | 71 | 72 | RequireAdministrator 73 | Windows 74 | 75 | 76 | PerMonitorHighDPIAware 77 | 78 | 79 | 80 | 81 | _WINDOWS;STRICT;_DEBUG;%(PreprocessorDefinitions) 82 | Disabled 83 | true 84 | EnableFastChecks 85 | MultiThreadedDebug 86 | Level4 87 | ProgramDatabase 88 | 89 | 90 | _DEBUG;%(PreprocessorDefinitions) 91 | 92 | 93 | true 94 | false 95 | 96 | 97 | 98 | 99 | 100 | _WINDOWS;STRICT;NDEBUG;%(PreprocessorDefinitions) 101 | MinSpace 102 | Size 103 | true 104 | MultiThreaded 105 | 106 | true 107 | true 108 | /Gw %(AdditionalOptions) 109 | 110 | 111 | NDEBUG;%(PreprocessorDefinitions) 112 | 113 | 114 | true 115 | true 116 | UseLinkTimeCodeGeneration 117 | true 118 | true 119 | true 120 | 121 | 122 | 123 | 124 | WIN32;%(PreprocessorDefinitions) 125 | 126 | 127 | MachineX86 128 | 129 | 130 | 131 | 132 | WIN64;%(PreprocessorDefinitions) 133 | 134 | 135 | MachineX64 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | Create 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/MainDlg.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "resource.h" 3 | 4 | #include "AboutDlg.h" 5 | #include "SettingsDlg.h" 6 | #include "MainDlg.h" 7 | 8 | BOOL CMainDlg::PreTranslateMessage(MSG* pMsg) 9 | { 10 | return CWindow::IsDialogMessage(pMsg); 11 | } 12 | 13 | BOOL CMainDlg::OnIdle() 14 | { 15 | return FALSE; 16 | } 17 | 18 | LRESULT CMainDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 19 | { 20 | CenterWindow(); 21 | 22 | HANDLE hIconLg = ::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_ICON_MAIN), IMAGE_ICON, 23 | ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); 24 | HANDLE hIconSm = ::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_ICON_MAIN), IMAGE_ICON, 25 | ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); 26 | SetIcon(static_cast(hIconLg), TRUE); 27 | SetIcon(static_cast(hIconSm), FALSE); 28 | 29 | CMessageLoop* pLoop = _Module.GetMessageLoop(); 30 | ATLASSERT(pLoop); 31 | pLoop->AddMessageFilter(this); 32 | pLoop->AddIdleHandler(this); 33 | 34 | UIAddChildWindowContainer(m_hWnd); 35 | 36 | CConfigMgr config; 37 | if ( !config.Init() ) 38 | { 39 | ReportError(config.LastError, IDS_ERR_CONFIGURATION); 40 | CloseDialog(0); 41 | return FALSE; 42 | } 43 | 44 | DoDataExchange(DDX_LOAD); 45 | PopulateVPNList(); 46 | 47 | ATLENSURE_SUCCEEDED(m_threadConNotify.Initialize()); 48 | ATLENSURE_SUCCEEDED(m_threadDisNotify.Initialize()); 49 | ATLENSURE_SUCCEEDED(m_threadKeepAlive.Initialize()); 50 | 51 | m_evt.Create(NULL, TRUE, FALSE, NULL); 52 | ATLENSURE_SUCCEEDED(m_threadConNotify.AddHandle(m_evt, this, NULL)); 53 | 54 | DWORD dwErr = ::RasConnectionNotification(static_cast(INVALID_HANDLE_VALUE), m_evt, RASCN_Connection); 55 | if ( dwErr != ERROR_SUCCESS ) 56 | return !ReportError(GetErrorString(dwErr), IDS_ERR_RASCONNECTIONNOTIFICATION); 57 | 58 | UpdateConnections(); 59 | UpdateUI(); 60 | CreateMenu(); 61 | 62 | return TRUE; 63 | } 64 | 65 | LRESULT CMainDlg::OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) 66 | { 67 | bHandled = FALSE; 68 | 69 | if ( wParam == SC_MINIMIZE ) 70 | { 71 | bHandled = TRUE; 72 | Minimize(); 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | LRESULT CMainDlg::OnUser(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) 79 | { 80 | bHandled = FALSE; 81 | 82 | // since icon disappears on dbl click, make sure no other icon receives the buttonup msg 83 | if ( lParam == WM_LBUTTONDBLCLK ) 84 | { 85 | m_bDblClick = true; 86 | } 87 | else if ( lParam == WM_LBUTTONUP && m_bDblClick ) 88 | { 89 | m_bDblClick = false; 90 | OnMenuOpen(0, 0, NULL, bHandled); 91 | } 92 | else if ( lParam == WM_RBUTTONUP ) 93 | { 94 | bHandled = TRUE; 95 | 96 | CMenuHandle popup = m_menu.GetSubMenu(0); 97 | CMenuHandle conn = popup.GetSubMenu(0); 98 | CMenuHandle disc = popup.GetSubMenu(1); 99 | 100 | for ( int i = conn.GetMenuItemCount(); i > 0 ; i-- ) 101 | conn.RemoveMenu(i - 1, MF_BYPOSITION); 102 | 103 | for ( int i = disc.GetMenuItemCount(); i > 0 ; i-- ) 104 | disc.RemoveMenu(i - 1, MF_BYPOSITION); 105 | 106 | // get items from combobox so they'll be sorted 107 | for ( int i = 0; i < m_cboConnections.GetCount(); i++ ) 108 | { 109 | CString sConn; 110 | m_cboConnections.GetLBText(i, sConn.GetBuffer(m_cboConnections.GetLBTextLen(i))); 111 | sConn.ReleaseBuffer(); 112 | 113 | if ( m_ConnMap.GetValueAt(m_ConnMap.FindKey(sConn)).m_hRasConn ) 114 | disc.AppendMenu(0, static_cast(0), sConn); 115 | else 116 | conn.AppendMenu(0, static_cast(0), sConn); 117 | } 118 | 119 | CString sNone((LPCWSTR)IDS_LBL_EMPTYLIST); 120 | if ( conn.GetMenuItemCount() == 0 ) 121 | conn.AppendMenu(MF_GRAYED, static_cast(0), sNone); 122 | if ( disc.GetMenuItemCount() == 0 ) 123 | disc.AppendMenu(MF_GRAYED, static_cast(0), sNone); 124 | 125 | CPoint mouse; 126 | ::GetCursorPos(&mouse); 127 | ::SetForegroundWindow(m_hWnd); 128 | 129 | popup.TrackPopupMenu(TPM_VERNEGANIMATION, mouse.x, mouse.y, m_hWnd); 130 | 131 | // KB 135788 132 | PostMessage(WM_NULL); 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | LRESULT CMainDlg::OnMenuCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) 139 | { 140 | CMenuHandle mh(reinterpret_cast(lParam)); 141 | int nMenu = PtrToInt(reinterpret_cast(wParam)); 142 | 143 | if ( mh.GetMenuItemID(nMenu) ) 144 | SendMessage(WM_COMMAND, mh.GetMenuItemID(nMenu), lParam); 145 | else 146 | { 147 | CString sMenu; 148 | int nLen = mh.GetMenuStringLen(nMenu, MF_BYPOSITION) + 1; 149 | 150 | mh.GetMenuString(nMenu, sMenu.GetBuffer(nLen), nLen, MF_BYPOSITION); 151 | sMenu.ReleaseBuffer(); 152 | 153 | CConnection& conn = m_ConnMap.GetValueAt(m_ConnMap.FindKey(sMenu)); 154 | if ( conn.m_hRasConn ) 155 | Disconnect(conn); 156 | else 157 | Connect(conn); 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | LRESULT CMainDlg::OnRestore(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) 164 | { 165 | bHandled = TRUE; 166 | 167 | NotifyIcon(false); 168 | ShowWindow(SW_SHOW); 169 | return BringWindowToTop(); 170 | } 171 | 172 | LRESULT CMainDlg::OnTaskbarCreated(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 173 | { 174 | NotifyIcon(true); 175 | return 0; 176 | } 177 | 178 | LRESULT CMainDlg::OnMenuOpen(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled) 179 | { 180 | return OnRestore(WM_VPNDIALERPLUS, 0, 0, bHandled); 181 | } 182 | 183 | LRESULT CMainDlg::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 184 | { 185 | CAboutDlg dlg; 186 | dlg.DoModal(); 187 | return 0; 188 | } 189 | 190 | LRESULT CMainDlg::OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 191 | { 192 | CloseDialog(wID); 193 | return 0; 194 | } 195 | 196 | void CMainDlg::CloseDialog(int nVal) 197 | { 198 | ATLENSURE_SUCCEEDED(m_threadConNotify.Shutdown()); 199 | ATLENSURE_SUCCEEDED(m_threadDisNotify.Shutdown()); 200 | ATLENSURE_SUCCEEDED(m_threadKeepAlive.Shutdown()); 201 | 202 | NotifyIcon(false); 203 | 204 | DestroyWindow(); 205 | ::PostQuitMessage(nVal); 206 | } 207 | 208 | LRESULT CMainDlg::OnBnClickedConnect(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 209 | { 210 | Connect(m_ConnMap.GetValueAt(m_ConnMap.FindKey(m_sSelectedConnection))); 211 | return 0; 212 | } 213 | 214 | LRESULT CMainDlg::OnBnClickedDisconnect(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 215 | { 216 | Disconnect(m_ConnMap.GetValueAt(m_ConnMap.FindKey(m_sSelectedConnection))); 217 | return 0; 218 | } 219 | 220 | LRESULT CMainDlg::OnBnClickedProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 221 | { 222 | RasDialog(m_sSelectedConnection); 223 | return 0; 224 | } 225 | 226 | LRESULT CMainDlg::OnBnClickedSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 227 | { 228 | CConfigMgr config; 229 | config.Init(); 230 | if ( !config.LoadConfig(!config.ConfigExists()) ) 231 | { 232 | if ( ReportError(_S(IDS_MSG_NEWCONFIG), IDS_ERR_INVALIDCONFIG, MB_YESNO | MB_ICONEXCLAMATION) == IDNO || !config.LoadConfig(true)) 233 | return ReportError(config.LastError, IDS_ERR_CONFIGURATION); 234 | } 235 | 236 | CSettingsDlg setdlg(m_ConnMap.GetValueAt(m_ConnMap.FindKey(m_sSelectedConnection))); 237 | setdlg.m_Conn.asRoutes.RemoveAll(); 238 | setdlg.m_Conn.sKeepAlive.Empty(); 239 | 240 | config.LoadConnection(setdlg.m_Conn); 241 | 242 | if ( setdlg.DoModal() && !config.SaveConnection(setdlg.m_Conn) ) 243 | return ReportError(config.LastError, IDS_ERR_CONFIGURATION); 244 | 245 | return 0; 246 | } 247 | 248 | LRESULT CMainDlg::OnBnClickedNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 249 | { 250 | CString sEmpty; 251 | RasDialog(sEmpty); 252 | PopulateVPNList(); 253 | 254 | return 0; 255 | } 256 | 257 | LRESULT CMainDlg::OnCbnSelchangeConnections(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) 258 | { 259 | if ( m_cboConnections.GetCurSel() == CB_ERR ) 260 | m_sSelectedConnection.Empty(); 261 | else 262 | { 263 | int nLen = m_cboConnections.GetLBTextLen(m_cboConnections.GetCurSel()); 264 | m_cboConnections.GetLBText(m_cboConnections.GetCurSel(), m_sSelectedConnection.GetBuffer(nLen)); 265 | m_sSelectedConnection.ReleaseBuffer(); 266 | } 267 | 268 | UpdateUI(); 269 | return 0; 270 | } 271 | 272 | bool CMainDlg::IsVpnConnection(LPCWSTR pszEntryName) 273 | { 274 | DWORD dwCb = 0; 275 | DWORD dwErr = ::RasGetEntryProperties(NULL, pszEntryName, NULL, &dwCb, NULL, NULL); 276 | if ( dwErr != ERROR_BUFFER_TOO_SMALL ) 277 | return !ReportError(GetErrorString(dwErr), IDS_ERR_RASGETENTRYPROPERTIES); 278 | 279 | CHeapPtr rasEntry; 280 | ATLENSURE(rasEntry.AllocateBytes(dwCb)); 281 | ::SecureZeroMemory(rasEntry.m_pData, dwCb); 282 | rasEntry->dwSize = sizeof(RASENTRY); 283 | 284 | dwErr = ::RasGetEntryProperties(NULL, pszEntryName, rasEntry, &dwCb, NULL, NULL); 285 | if ( dwErr != ERROR_SUCCESS ) 286 | return !ReportError(GetErrorString(dwErr), IDS_ERR_RASGETENTRYPROPERTIES); 287 | 288 | return rasEntry->dwType == RASET_Vpn; 289 | } 290 | 291 | void CMainDlg::PopulateVPNList() 292 | { 293 | DWORD dwCb = 0; 294 | DWORD dwEntries = 0; 295 | DWORD dwErr = ::RasEnumEntries(NULL, NULL, NULL, &dwCb, &dwEntries); 296 | if ( dwErr == ERROR_SUCCESS ) 297 | return; 298 | 299 | if ( dwErr != ERROR_BUFFER_TOO_SMALL ) 300 | { 301 | ReportError(GetErrorString(dwErr), IDS_ERR_RASENUMENTRIES); 302 | return; 303 | } 304 | 305 | CHeapPtr rasEntryNames; 306 | ATLENSURE(rasEntryNames.AllocateBytes(dwCb)); 307 | ::SecureZeroMemory(rasEntryNames.m_pData, dwCb); 308 | rasEntryNames->dwSize = sizeof(RASENTRYNAME); 309 | 310 | dwErr = ::RasEnumEntries(NULL, NULL, rasEntryNames, &dwCb, &dwEntries); 311 | if ( dwErr != ERROR_SUCCESS ) 312 | { 313 | ReportError(GetErrorString(dwErr), IDS_ERR_RASENUMENTRIES); 314 | return; 315 | } 316 | 317 | CConfigMgr config; 318 | bool configure = config.Init() && config.LoadConfig(); 319 | 320 | for ( DWORD i = 0; i < dwEntries; i++ ) 321 | { 322 | CString sName = rasEntryNames[i].szEntryName; 323 | if ( IsVpnConnection(sName) && m_ConnMap.FindKey(sName) == -1 ) 324 | { 325 | CConnection conn(sName); 326 | if ( configure ) 327 | config.LoadConnection(conn); 328 | 329 | m_ConnMap.Add(sName, conn); 330 | m_cboConnections.AddString(sName); 331 | } 332 | } 333 | } 334 | 335 | void CMainDlg::UpdateConnections() 336 | { 337 | DWORD dwCb = 0; 338 | DWORD dwEntries = 0; 339 | DWORD dwErr = ::RasEnumConnections(NULL, &dwCb, &dwEntries); 340 | if ( dwErr == ERROR_SUCCESS ) 341 | return; 342 | 343 | if ( dwErr != ERROR_BUFFER_TOO_SMALL ) 344 | { 345 | ReportError(GetErrorString(dwErr), IDS_ERR_RASENUMCONNECTIONS); 346 | return; 347 | } 348 | 349 | CHeapPtr rasConns; 350 | ATLENSURE(rasConns.AllocateBytes(dwCb)); 351 | ::SecureZeroMemory(rasConns.m_pData, dwCb); 352 | rasConns->dwSize = sizeof(RASCONN); 353 | 354 | dwErr = ::RasEnumConnections(rasConns, &dwCb, &dwEntries); 355 | if ( dwErr != ERROR_SUCCESS ) 356 | { 357 | ReportError(GetErrorString(dwErr), IDS_ERR_RASENUMCONNECTIONS); 358 | return; 359 | } 360 | 361 | for ( DWORD i = 0; i < dwEntries; i++ ) 362 | { 363 | RASCONNSTATUS rcs = {0}; 364 | rcs.dwSize = sizeof(RASCONNSTATUS); 365 | 366 | ::RasGetConnectStatus(rasConns[i].hrasconn, &rcs); 367 | if ( rcs.rasconnstate == RASCS_Connected ) 368 | { 369 | int nPos = m_ConnMap.FindKey(CString(rasConns[i].szEntryName)); 370 | if ( nPos != -1 ) 371 | { 372 | CConnection& conn = m_ConnMap.GetValueAt(nPos); 373 | conn.m_hRasConn = rasConns[i].hrasconn; 374 | 375 | if ( !conn.m_bConnected ) 376 | PostConnect(conn); 377 | } 378 | } 379 | } 380 | } 381 | 382 | void CMainDlg::UpdateUI() 383 | { 384 | if ( m_sSelectedConnection.IsEmpty() ) 385 | { 386 | m_stcStatus.SetWindowText(EMPTY_STRING); 387 | 388 | m_btnConnect.EnableWindow(FALSE); 389 | m_btnDisconnect.EnableWindow(FALSE); 390 | m_btnSettings.EnableWindow(FALSE); 391 | m_btnProperties.EnableWindow(FALSE); 392 | } 393 | else 394 | { 395 | m_btnConnect.EnableWindow(); 396 | m_btnDisconnect.EnableWindow(); 397 | m_btnSettings.EnableWindow(); 398 | m_btnProperties.EnableWindow(); 399 | 400 | if ( m_ConnMap.GetValueAt(m_ConnMap.FindKey(m_sSelectedConnection)).m_hRasConn ) 401 | { 402 | m_btnConnect.ShowWindow(SW_HIDE); 403 | m_btnDisconnect.ShowWindow(SW_SHOW); 404 | 405 | m_stcStatus.SetWindowText(_S(IDS_STATUS_CONNECTED)); 406 | } 407 | else 408 | { 409 | m_btnConnect.ShowWindow(SW_SHOW); 410 | m_btnDisconnect.ShowWindow(SW_HIDE); 411 | 412 | m_stcStatus.SetWindowText(EMPTY_STRING); 413 | } 414 | } 415 | } 416 | 417 | void CMainDlg::Connect(CConnection& conn) 418 | { 419 | RASENTRY rasEntry = {0}; 420 | rasEntry.dwSize = sizeof(RASENTRY); 421 | 422 | DWORD dwErr = ::RasGetEntryProperties(NULL, conn.sName, &rasEntry, &rasEntry.dwSize, NULL, NULL); 423 | if ( dwErr != ERROR_SUCCESS ) 424 | { 425 | ReportError(GetErrorString(dwErr), IDS_ERR_RASGETENTRYPROPERTIES); 426 | return; 427 | } 428 | 429 | BOOL bDoLogon = (rasEntry.dwfOptions & RASEO_UseLogonCredentials) != RASEO_UseLogonCredentials; 430 | BOOL bPasswordSaved = FALSE; 431 | 432 | RASDIALPARAMS rasDialParams = {0}; 433 | rasDialParams.dwSize = sizeof(RASDIALPARAMS); 434 | rasDialParams.dwCallbackId = reinterpret_cast(this); 435 | ATLENSURE_SUCCEEDED(::StringCchCopy(rasDialParams.szEntryName, RAS_MaxEntryName, conn.sName)); 436 | 437 | dwErr = ::RasGetEntryDialParams(NULL, &rasDialParams, &bPasswordSaved); 438 | if ( dwErr != ERROR_SUCCESS ) 439 | { 440 | ReportError(GetErrorString(dwErr), IDS_ERR_RASDIALGETENTRYDIALPARAMS); 441 | return; 442 | } 443 | 444 | if ( !bPasswordSaved && bDoLogon ) 445 | { 446 | CString sPrompt = _S(IDS_MSG_CREDENTIALS); 447 | CREDUI_INFO credInfo = {0}; 448 | credInfo.cbSize = sizeof(CREDUI_INFO); 449 | credInfo.hwndParent = m_hWnd; 450 | credInfo.pszCaptionText = m_sSelectedConnection; 451 | credInfo.pszMessageText = sPrompt; 452 | 453 | DWORD cbCred = 0; 454 | ::CredPackAuthenticationBuffer(CRED_PACK_PROTECTED_CREDENTIALS, rasDialParams.szUserName, L"", NULL, &cbCred); 455 | 456 | PBYTE pBuff = static_cast(_malloca(cbCred)); 457 | ATLENSURE(::CredPackAuthenticationBuffer(CRED_PACK_PROTECTED_CREDENTIALS, rasDialParams.szUserName, L"", pBuff, &cbCred)); 458 | 459 | LPVOID pCred; 460 | ULONG ulPkg = 0; 461 | dwErr = ::CredUIPromptForWindowsCredentials(&credInfo, 0, &ulPkg, pBuff, cbCred, &pCred, &cbCred, NULL, CREDUIWIN_GENERIC); 462 | _freea(pBuff); 463 | 464 | if ( dwErr == ERROR_CANCELLED ) 465 | return; 466 | 467 | DWORD unlen = UNLEN; 468 | DWORD dnlen = DNLEN; 469 | DWORD pwlen = PWLEN; 470 | ATLENSURE(::CredUnPackAuthenticationBuffer(CRED_PACK_PROTECTED_CREDENTIALS, pCred, cbCred, rasDialParams.szUserName, &unlen, rasDialParams.szDomain, &dnlen, rasDialParams.szPassword, &pwlen)); 471 | 472 | ::SecureZeroMemory(pCred, cbCred); 473 | ::CoTaskMemFree(pCred); 474 | } 475 | 476 | dwErr = ::RasDial(NULL, NULL, &rasDialParams, 2, &CMainDlg::RasDialCallback, &conn.m_hRasConn); 477 | ::SecureZeroMemory(&rasDialParams, sizeof(rasDialParams)); 478 | 479 | if ( dwErr != ERROR_SUCCESS ) 480 | { 481 | ReportError(GetErrorString(dwErr), IDS_ERR_RASDIAL); 482 | return; 483 | } 484 | 485 | UpdateUI(); 486 | } 487 | 488 | void CMainDlg::Disconnect(CConnection& conn) 489 | { 490 | CCursor cur; 491 | cur.LoadSysCursor(IDC_WAIT); 492 | SetCursor(cur); 493 | m_btnDisconnect.EnableWindow(FALSE); 494 | 495 | ::RasHangUp(conn.m_hRasConn); 496 | conn.m_bConnected = false; 497 | conn.m_hRasConn = NULL; 498 | if ( conn.m_timer ) 499 | { 500 | ATLENSURE_SUCCEEDED(m_threadKeepAlive.RemoveHandle(conn.m_timer)); 501 | conn.m_timer.m_h = NULL; 502 | } 503 | 504 | m_btnDisconnect.EnableWindow(); 505 | cur.DestroyCursor(); 506 | cur.LoadSysCursor(IDC_ARROW); 507 | SetCursor(cur); 508 | 509 | UpdateUI(); 510 | } 511 | 512 | void CMainDlg::PostConnect(CConnection& conn) 513 | { 514 | if ( conn.asRoutes.GetSize() > 0 ) 515 | { 516 | if ( conn.sName == m_sSelectedConnection ) 517 | { 518 | m_stcStatus.SetWindowText(_S(IDS_STATUS_ADDINGROUTES)); 519 | ::Sleep(600); // purely cosmetic, so there's time to read the status 520 | } 521 | 522 | RASPPPIP rasIP = {0}; 523 | rasIP.dwSize = sizeof(rasIP); 524 | 525 | DWORD dwCb = sizeof(rasIP); 526 | DWORD dwErr = ::RasGetProjectionInfo(conn.m_hRasConn, RASP_PppIp, &rasIP, &dwCb); 527 | if ( dwErr != ERROR_SUCCESS ) 528 | { 529 | ReportError(GetErrorString(dwErr), IDS_ERR_RASGETPROJECTIONINFO); 530 | return; 531 | } 532 | 533 | IPAddr ulIP = ::inet_addr(CW2A(rasIP.szIpAddress)); 534 | 535 | dwCb = 0; 536 | dwErr = ::GetIpForwardTable(NULL, &dwCb, FALSE); 537 | if ( dwErr != ERROR_INSUFFICIENT_BUFFER ) 538 | { 539 | ReportError(GetErrorString(dwErr), IDS_ERR_GETIPFORWARDTABLE); 540 | return; 541 | } 542 | 543 | CHeapPtr routeTable; 544 | ATLENSURE(routeTable.AllocateBytes(dwCb)); 545 | ::SecureZeroMemory(routeTable.m_pData, dwCb); 546 | 547 | dwErr = ::GetIpForwardTable(routeTable, &dwCb, FALSE); 548 | if ( dwErr != ERROR_SUCCESS ) 549 | { 550 | ReportError(GetErrorString(dwErr), IDS_ERR_GETIPFORWARDTABLE); 551 | return; 552 | } 553 | 554 | MIB_IPFORWARDROW route = {0}; 555 | for ( u_long i = 0; i < routeTable->dwNumEntries; i++ ) 556 | { 557 | if ( routeTable->table[i].dwForwardNextHop == ulIP ) 558 | { 559 | if ( route.dwForwardNextHop == 0UL || routeTable->table[i].dwForwardProto != MIB_IPPROTO_LOCAL ) 560 | ::memcpy_s(&route, sizeof(MIB_IPFORWARDROW), &routeTable->table[i], sizeof(MIB_IPFORWARDROW)); 561 | 562 | if ( routeTable->table[i].dwForwardProto == MIB_IPPROTO_LOCAL ) 563 | continue; 564 | 565 | dwErr = ::DeleteIpForwardEntry(&route); 566 | if ( dwErr != ERROR_SUCCESS ) 567 | { 568 | ReportError(GetErrorString(dwErr), IDS_ERR_DELETEIPFORWARDENTRY); 569 | //return; 570 | } 571 | } 572 | } 573 | 574 | if ( route.dwForwardNextHop != ulIP ) 575 | { 576 | ReportError(_S(IDS_MSG_NOELIGIBLEROUTE), IDS_ERR_CREATEIPFORWARDENTRY); 577 | return; 578 | } 579 | 580 | for ( int i = 0; i < conn.asRoutes.GetSize(); i++ ) 581 | { 582 | IN_ADDR iaNet, iaMask; 583 | LPCWSTR szRoute = conn.asRoutes[i]; 584 | ::RtlIpv4StringToAddress(szRoute, TRUE, &szRoute, &iaNet); 585 | ::ConvertLengthToIpv4Mask(::StrToInt(szRoute + 1), &iaMask.s_addr); 586 | 587 | route.dwForwardDest = iaNet.s_addr; 588 | route.dwForwardMask = iaMask.s_addr; 589 | route.dwForwardType = MIB_IPNET_TYPE_DYNAMIC; 590 | route.dwForwardProto = MIB_IPPROTO_NETMGMT; 591 | 592 | dwErr = ::CreateIpForwardEntry(&route); 593 | if ( dwErr != ERROR_SUCCESS ) 594 | { 595 | ReportError(GetErrorString(dwErr), IDS_ERR_CREATEIPFORWARDENTRY); 596 | //return; 597 | } 598 | } 599 | } 600 | 601 | if ( !conn.sKeepAlive.IsEmpty() ) 602 | ATLENSURE_SUCCEEDED(m_threadKeepAlive.AddTimer(6000, this, (DWORD_PTR)&conn, &conn.m_timer.m_h)); 603 | 604 | if ( !conn.m_evt ) 605 | { 606 | conn.m_evt.Create(NULL, TRUE, FALSE, NULL); 607 | ATLENSURE_SUCCEEDED(m_threadDisNotify.AddHandle(conn.m_evt, this, (DWORD_PTR)&conn)); 608 | } 609 | 610 | DWORD dwErr = ::RasConnectionNotification(conn.m_hRasConn, conn.m_evt, RASCN_Disconnection); 611 | if ( dwErr != ERROR_SUCCESS ) 612 | { 613 | ReportError(GetErrorString(dwErr), IDS_ERR_RASCONNECTIONNOTIFICATION); 614 | //return; 615 | } 616 | 617 | conn.m_bConnected = true; 618 | } 619 | 620 | void CMainDlg::RasDialog(const CString& sConnName) 621 | { 622 | RASENTRYDLG rasDlg = {0}; 623 | rasDlg.dwSize = sizeof(RASENTRYDLG); 624 | rasDlg.hwndOwner = m_hWnd; 625 | rasDlg.dwFlags = RASEDFLAG_NoRename; 626 | 627 | LPWSTR lpszConn = NULL; 628 | if ( sConnName.IsEmpty() ) 629 | rasDlg.dwFlags |= RASEDFLAG_NewTunnelEntry; 630 | else 631 | lpszConn = const_cast(sConnName).GetBuffer(0); 632 | 633 | if ( !::RasEntryDlg(NULL, lpszConn, &rasDlg) && rasDlg.dwError != ERROR_SUCCESS ) 634 | ReportError(GetErrorString(rasDlg.dwError), IDS_ERR_RASENTRYDLG); 635 | } 636 | 637 | void CMainDlg::Minimize() 638 | { 639 | NotifyIcon(true); 640 | ShowWindow(SW_HIDE); 641 | 642 | ::SetProcessWorkingSetSize(::GetCurrentProcess(), static_cast(-1), static_cast(-1)); 643 | } 644 | 645 | void CMainDlg::NotifyIcon(bool bShow) 646 | { 647 | CIcon icon; 648 | icon.LoadIcon(IDR_ICON_MAIN, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON)); 649 | 650 | NOTIFYICONDATA nid = {0}; 651 | nid.cbSize = sizeof(NOTIFYICONDATA); 652 | nid.hWnd = m_hWnd; 653 | nid.uID = 75; 654 | nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; 655 | nid.uCallbackMessage = WM_USER; 656 | nid.hIcon = icon.m_hIcon; 657 | ATLENSURE_SUCCEEDED(::StringCchCopy(nid.szTip, _countof(nid.szTip), _S(IDS_NIF_TIP))); 658 | 659 | ::Shell_NotifyIcon(bShow ? NIM_ADD : NIM_DELETE, &nid); 660 | } 661 | 662 | void CMainDlg::CreateMenu() 663 | { 664 | m_menu.DestroyMenu(); 665 | m_menu.LoadMenu(IDR_MENU_POPUP); 666 | 667 | MENUINFO mi = {0}; 668 | mi.cbSize = sizeof(MENUINFO); 669 | mi.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS; 670 | m_menu.GetMenuInfo(&mi); 671 | 672 | mi.dwStyle |= MNS_NOTIFYBYPOS; 673 | m_menu.SetMenuInfo(&mi); 674 | 675 | m_menu.GetSubMenu(0).SetMenuDefaultItem(4, TRUE); 676 | } 677 | 678 | int CMainDlg::ReportError(LPCWSTR szErr, UINT_PTR nRes, UINT nType) 679 | { 680 | return MessageBox(szErr, _S(nRes), nType); 681 | } 682 | 683 | CString CMainDlg::GetErrorString(DWORD dwErr) 684 | { 685 | dwErr = dwErr == 0 ? ::GetLastError() : dwErr; 686 | CString sErr; 687 | LPWSTR lpMsgBuf = NULL; 688 | 689 | if ( dwErr >= RASBASE && dwErr <= RASBASEEND ) 690 | { 691 | ::RasGetErrorString(dwErr, sErr.GetBuffer(512), 512); 692 | sErr.ReleaseBuffer(); 693 | } 694 | else if ( ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, 695 | dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&lpMsgBuf), 0, NULL) ) 696 | { 697 | sErr = lpMsgBuf; 698 | ::LocalFree(lpMsgBuf); 699 | } 700 | else 701 | ATLENSURE(sErr.LoadString(IDS_ERR_UNKNOWN)); 702 | 703 | sErr.AppendFormat(IDS_FMT_ERRORCODE, static_cast(dwErr), dwErr); 704 | return sErr; 705 | } 706 | 707 | void CALLBACK CMainDlg::RasDialCallback(ULONG_PTR dwCallbackId, DWORD /*dwSubEntry*/, HRASCONN hRasConn, UINT /*unMsg*/, RASCONNSTATE RasConnState, DWORD dwError, DWORD /*dwExtendedError*/) 708 | { 709 | CMainDlg* pMainDlg = reinterpret_cast(dwCallbackId); 710 | CConnection* pConn = NULL; 711 | 712 | for ( int i = 0; i < pMainDlg->m_ConnMap.GetSize(); i++ ) 713 | { 714 | CConnection& conn = pMainDlg->m_ConnMap.GetValueAt(i); 715 | if ( conn.m_hRasConn == hRasConn ) 716 | pConn = &conn; 717 | } 718 | 719 | if ( !pConn ) 720 | return; 721 | 722 | CString sMsg; 723 | switch ( RasConnState ) 724 | { 725 | case RASCS_OpenPort : ATLENSURE(sMsg.LoadString(IDS_STATUS_OPENINGPORT)); break; 726 | case RASCS_ConnectDevice : ATLENSURE(sMsg.LoadString(IDS_STATUS_CONNECTING)); break; 727 | case RASCS_Authenticate : ATLENSURE(sMsg.LoadString(IDS_STATUS_AUTHENTICATING)); break; 728 | case RASCS_AuthProject : ATLENSURE(sMsg.LoadString(IDS_STATUS_PROJECTING)); break; 729 | case RASCS_Connected : ATLENSURE(sMsg.LoadString(IDS_STATUS_CONNECTED)); break; 730 | } 731 | 732 | if ( !sMsg.IsEmpty() && pConn->sName == pMainDlg->m_sSelectedConnection ) 733 | pMainDlg->m_stcStatus.SetWindowText(sMsg); 734 | 735 | if ( dwError != ERROR_SUCCESS ) 736 | { 737 | pMainDlg->Disconnect(*pConn); 738 | 739 | if ( pConn->sName == pMainDlg->m_sSelectedConnection ) 740 | pMainDlg->m_stcStatus.SetWindowText(GetErrorString(dwError)); 741 | } 742 | } 743 | 744 | HRESULT CMainDlg::Execute(DWORD_PTR dwParam, HANDLE hObject) 745 | { 746 | if ( m_evt == hObject ) 747 | { 748 | m_evt.Reset(); 749 | UpdateConnections(); 750 | UpdateUI(); 751 | } 752 | else 753 | { 754 | CConnection& conn = *reinterpret_cast(dwParam); 755 | if ( conn.m_evt == hObject ) 756 | { 757 | conn.m_evt.Reset(); 758 | Disconnect(conn); 759 | } 760 | else if ( conn.m_timer == hObject ) 761 | { 762 | CHAR SendData[] = "VPN Dialer+ Keep-Alive ICMP Echo"; 763 | CHAR ReplyBuffer[sizeof(ICMP_ECHO_REPLY) + _countof(SendData) - 1 + 8] = {0}; 764 | 765 | HANDLE hIcmp = ::IcmpCreateFile(); 766 | ::IcmpSendEcho(hIcmp, inet_addr(CW2A(conn.sKeepAlive)), SendData, _countof(SendData) - 1, NULL, ReplyBuffer, _countof(ReplyBuffer), 2000); 767 | ::IcmpCloseHandle(hIcmp); 768 | } 769 | } 770 | 771 | return S_OK; 772 | } 773 | 774 | HRESULT CMainDlg::CloseHandle(HANDLE hObject) 775 | { 776 | if ( m_evt == hObject ) 777 | m_evt.Close(); 778 | else 779 | for ( int i = 0; i < m_ConnMap.GetSize(); i++ ) 780 | { 781 | CConnection& conn = m_ConnMap.GetValueAt(i); 782 | if ( conn.m_evt == hObject ) 783 | conn.m_evt.Close(); 784 | else if ( conn.m_timer == hObject ) 785 | conn.m_timer.Close(); 786 | } 787 | 788 | return S_OK; 789 | } 790 | --------------------------------------------------------------------------------