├── 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 | 
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 | 
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 |
--------------------------------------------------------------------------------