mirror of https://github.com/OpenVPN/openvpn-gui
Implement importing profile from a generic URL
ParseUrl extended to parse generic URLs and parse the path. DownloadProfile() function re-factored for reuse with generic URL. Also: - INTERNET_FLAG_RELOAD added to the request call to force reloading the data from server instead of using possibly cached data. - Input box for URL extended in length to about 50 characters wide. Signed-off-by: Selva Nair <selva.nair@gmail.com>pull/449/head
parent
480d9e456b
commit
e80a39c825
128
as.c
128
as.c
|
@ -44,7 +44,7 @@
|
||||||
* Profile name is either (sorted in priority order):
|
* Profile name is either (sorted in priority order):
|
||||||
* - value of OVPN_ACCESS_SERVER_FRIENDLY_NAME
|
* - value of OVPN_ACCESS_SERVER_FRIENDLY_NAME
|
||||||
* - value of OVPN_ACCESS_SERVER_PROFILE
|
* - value of OVPN_ACCESS_SERVER_PROFILE
|
||||||
* - URL
|
* - specified default_name
|
||||||
*
|
*
|
||||||
* @param profile profile content
|
* @param profile profile content
|
||||||
* @param default_name default name for profile if it doesn't contain name
|
* @param default_name default name for profile if it doesn't contain name
|
||||||
|
@ -88,9 +88,10 @@ ExtractProfileName(const WCHAR *profile, const WCHAR *default_name, WCHAR *out_n
|
||||||
out_name[out_name_length - 1] = L'\0';
|
out_name[out_name_length - 1] = L'\0';
|
||||||
|
|
||||||
/* sanitize profile name */
|
/* sanitize profile name */
|
||||||
|
const char *reserved = "<>:\"/\\|?*;"; /* remap these and ascii 1 to 31 */
|
||||||
while (*out_name) {
|
while (*out_name) {
|
||||||
wchar_t c = *out_name;
|
wchar_t c = *out_name;
|
||||||
if (c == L'<' || c == L'>' || c == L':' || c == L'\"' || c == L'/' || c == L'\\' || c == L'|' || c == L'?' || c == L'*')
|
if (c < 32 || strchr(reserved, c))
|
||||||
*out_name = L'_';
|
*out_name = L'_';
|
||||||
++out_name;
|
++out_name;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +112,7 @@ struct UrlComponents
|
||||||
{
|
{
|
||||||
int port;
|
int port;
|
||||||
WCHAR host[URL_LEN];
|
WCHAR host[URL_LEN];
|
||||||
|
WCHAR path[URL_LEN];
|
||||||
bool https;
|
bool https;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,27 +126,33 @@ ParseUrl(const WCHAR *url, struct UrlComponents* comps)
|
||||||
{
|
{
|
||||||
ZeroMemory(comps, sizeof(struct UrlComponents));
|
ZeroMemory(comps, sizeof(struct UrlComponents));
|
||||||
|
|
||||||
int domain_off = 0;
|
|
||||||
comps->port = 443;
|
comps->port = 443;
|
||||||
comps->https = true;
|
comps->https = true;
|
||||||
if (wcsbegins(url, L"http://")) {
|
if (wcsbegins(url, L"http://")) {
|
||||||
domain_off = 7;
|
url += 7;
|
||||||
} else if (wcsbegins(url, L"https://")) {
|
} else if (wcsbegins(url, L"https://")) {
|
||||||
domain_off = 8;
|
url +=8;
|
||||||
}
|
}
|
||||||
|
|
||||||
WCHAR* strport = wcsstr(url + domain_off, L":");
|
WCHAR *strport = wcsstr(url, L":");
|
||||||
|
WCHAR *pathptr = wcsstr(url, L"/");
|
||||||
if (strport) {
|
if (strport) {
|
||||||
WCHAR* end;
|
wcsncpy_s(comps->host, URL_LEN, url, strport - url);
|
||||||
wcsncpy(comps->host, url + domain_off, strport - url - domain_off);
|
comps->port = wcstol(strport + 1, NULL, 10);
|
||||||
comps->port = wcstol(strport + 1, &end, 10);
|
|
||||||
}
|
}
|
||||||
else {
|
else if (pathptr)
|
||||||
wcscpy(comps->host, url + domain_off);
|
{
|
||||||
|
wcsncpy_s(comps->host, URL_LEN, url, pathptr - url);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wcsncpy_s(comps->host, URL_LEN, url, _TRUNCATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comps->host[wcslen(comps->host) - 1] == L'/')
|
if (pathptr)
|
||||||
comps->host[wcslen(comps->host) - 1] = L'\0';
|
{
|
||||||
|
wcsncpy_s(comps->path, URL_LEN, pathptr + 1, _TRUNCATE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -270,19 +278,38 @@ CRDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download profile from AS and save it to a special-named temp file
|
* Construct the REST URL for AS profile
|
||||||
|
*
|
||||||
|
* @param host AS hostname, entered by user, might contain protocol and port
|
||||||
|
* @param autologin should autologin profile be used
|
||||||
|
* @param comps Pointer to UrlComponents. Value assigned by this function.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
GetASUrl(const WCHAR *host, bool autologin, struct UrlComponents *comps)
|
||||||
|
{
|
||||||
|
|
||||||
|
ParseUrl(host, comps);
|
||||||
|
|
||||||
|
swprintf(comps->path, URL_LEN, L"/rest/%ls?tls-cryptv2=1&action=import", autologin ? L"GetAutologin" : L"GetUserlogin");
|
||||||
|
comps->path[URL_LEN - 1] = L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download profile from a generic URL and save it to a temp file
|
||||||
*
|
*
|
||||||
* @param hWnd handle of window which initiated download
|
* @param hWnd handle of window which initiated download
|
||||||
* @param host AS hostname, entered by user, might contain protocol and port
|
* @param comps pointer to struct UrlComponents describing the URL
|
||||||
* @param username UTF-8 encoded username used for HTTP basic auth
|
* @param username UTF-8 encoded username used for HTTP basic auth
|
||||||
* @param password UTF-8 encoded password used for HTTP basic auth
|
* @param password UTF-8 encoded password used for HTTP basic auth
|
||||||
* @param autologin should autologin profile be used
|
|
||||||
* @param out_path full path to where profile is downloaded. Value assigned by this function.
|
* @param out_path full path to where profile is downloaded. Value assigned by this function.
|
||||||
* @param out_path_size number of elements in out_path arrray
|
* @param out_path_size number of elements in out_path arrray
|
||||||
|
*
|
||||||
|
* Filename in out_path is parsed from tags in received data
|
||||||
|
* with the url hostname as a fallback.
|
||||||
*/
|
*/
|
||||||
BOOL
|
static BOOL
|
||||||
DownloadProfile(HANDLE hWnd, const WCHAR *host, const char *username, const char *password_orig,
|
DownloadProfile(HANDLE hWnd, const struct UrlComponents *comps, const char *username,
|
||||||
BOOL autologin, WCHAR *out_path, size_t out_path_size)
|
const char *password_orig, WCHAR *out_path, size_t out_path_size)
|
||||||
{
|
{
|
||||||
HANDLE hInternet = NULL;
|
HANDLE hInternet = NULL;
|
||||||
HANDLE hConnect = NULL;
|
HANDLE hConnect = NULL;
|
||||||
|
@ -290,9 +317,9 @@ DownloadProfile(HANDLE hWnd, const WCHAR *host, const char *username, const char
|
||||||
BOOL result = FALSE;
|
BOOL result = FALSE;
|
||||||
char* buf = NULL;
|
char* buf = NULL;
|
||||||
|
|
||||||
|
/* need to make copy of password to use it for dynamic response */
|
||||||
char password[USER_PASS_LEN] = { 0 };
|
char password[USER_PASS_LEN] = { 0 };
|
||||||
strncpy(password, password_orig, USER_PASS_LEN - 1);
|
strncpy_s(password, _countof(password), password_orig, _TRUNCATE);
|
||||||
password[USER_PASS_LEN - 1] = '\0';
|
|
||||||
|
|
||||||
hInternet = InternetOpenW(L"openvpn-gui/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
hInternet = InternetOpenW(L"openvpn-gui/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
||||||
if (!hInternet) {
|
if (!hInternet) {
|
||||||
|
@ -300,22 +327,18 @@ DownloadProfile(HANDLE hWnd, const WCHAR *host, const char *username, const char
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UrlComponents comps = { 0 };
|
|
||||||
ParseUrl(host, &comps);
|
|
||||||
|
|
||||||
/* wait cursor will be automatically reverted later */
|
/* wait cursor will be automatically reverted later */
|
||||||
SetCursor(LoadCursorW(0, IDC_WAIT));
|
SetCursor(LoadCursorW(0, IDC_WAIT));
|
||||||
|
|
||||||
hConnect = InternetConnectW(hInternet, comps.host, comps.port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
|
hConnect = InternetConnectW(hInternet, comps->host, comps->port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
|
||||||
if (!hConnect) {
|
if (!hConnect) {
|
||||||
ShowWinInetError(hWnd);
|
ShowWinInetError(hWnd);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
WCHAR obj_name[URL_LEN] = { 0 };
|
DWORD req_flags = INTERNET_FLAG_RELOAD; /* load from server, do not use cached data */
|
||||||
swprintf(obj_name, URL_LEN, L"/rest/%ls?tls-cryptv2=1&action=import", autologin ? L"GetAutologin" : L"GetUserlogin");
|
req_flags |= comps->https ? INTERNET_FLAG_SECURE : 0;
|
||||||
obj_name[URL_LEN - 1] = L'\0';
|
hRequest = HttpOpenRequestW(hConnect, NULL, comps->path, NULL, NULL, NULL, req_flags, 0);
|
||||||
hRequest = HttpOpenRequestW(hConnect, NULL, obj_name, NULL, NULL, NULL, comps.https ? INTERNET_FLAG_SECURE : 0, 0);
|
|
||||||
if (!hRequest) {
|
if (!hRequest) {
|
||||||
ShowWinInetError(hWnd);
|
ShowWinInetError(hWnd);
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -423,7 +446,7 @@ again:
|
||||||
MessageBoxW(hWnd, L"Failed to convert profile content to wchar", _T(PACKAGE_NAME), MB_OK);
|
MessageBoxW(hWnd, L"Failed to convert profile content to wchar", _T(PACKAGE_NAME), MB_OK);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ExtractProfileName(wbuf, comps.host, name, MAX_PATH);
|
ExtractProfileName(wbuf, comps->host, name, MAX_PATH);
|
||||||
free(wbuf);
|
free(wbuf);
|
||||||
|
|
||||||
/* save profile content into tmp file */
|
/* save profile content into tmp file */
|
||||||
|
@ -460,38 +483,53 @@ done:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
server_as = 1,
|
||||||
|
server_generic = 2
|
||||||
|
} server_type_t;
|
||||||
|
|
||||||
INT_PTR CALLBACK
|
INT_PTR CALLBACK
|
||||||
ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
WCHAR url[URL_LEN] = {0};
|
WCHAR url[URL_LEN] = {0};
|
||||||
BOOL autologin = FALSE;
|
BOOL autologin = FALSE;
|
||||||
|
server_type_t type;
|
||||||
|
|
||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
|
type = (server_type_t) lParam;
|
||||||
|
SetProp(hwndDlg, cfgProp, (HANDLE)lParam);
|
||||||
SetStatusWinIcon(hwndDlg, ID_ICO_APP);
|
SetStatusWinIcon(hwndDlg, ID_ICO_APP);
|
||||||
|
|
||||||
/* disable OK button by default - not disabled in resources */
|
if (type == server_generic)
|
||||||
|
{
|
||||||
|
/* Change window title and hide autologin checkbox */
|
||||||
|
SetWindowTextW(hwndDlg, LoadLocalizedString(IDS_MENU_IMPORT_URL));
|
||||||
|
ShowWindow(GetDlgItem(hwndDlg, ID_CHK_AUTOLOGIN), SW_HIDE);
|
||||||
|
}
|
||||||
|
/* disable OK button until required data is filled in */
|
||||||
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
|
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
|
type = (server_type_t) GetProp(hwndDlg, cfgProp);
|
||||||
switch (LOWORD(wParam))
|
switch (LOWORD(wParam))
|
||||||
{
|
{
|
||||||
case ID_EDT_AUTH_USER:
|
case ID_EDT_AUTH_USER:
|
||||||
case ID_EDT_AUTH_PASS:
|
case ID_EDT_AUTH_PASS:
|
||||||
case ID_EDT_URL:
|
case ID_EDT_URL:
|
||||||
if (HIWORD(wParam) == EN_UPDATE) {
|
if (HIWORD(wParam) == EN_UPDATE) {
|
||||||
/* enable OK button only if url and username are filled */
|
/* enable OK button only if url and username (for AS only) are filled */
|
||||||
BOOL enableOK = GetWindowTextLengthW(GetDlgItem(hwndDlg, ID_EDT_URL))
|
BOOL enableOK = GetWindowTextLengthW(GetDlgItem(hwndDlg, ID_EDT_URL))
|
||||||
&& GetWindowTextLengthW(GetDlgItem(hwndDlg, ID_EDT_AUTH_USER));
|
&& (type == server_generic
|
||||||
|
|| GetWindowTextLengthW(GetDlgItem(hwndDlg, ID_EDT_AUTH_USER)));
|
||||||
EnableWindow(GetDlgItem(hwndDlg, IDOK), enableOK);
|
EnableWindow(GetDlgItem(hwndDlg, IDOK), enableOK);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDOK:
|
case IDOK:
|
||||||
autologin = IsDlgButtonChecked(hwndDlg, ID_CHK_AUTOLOGIN) == BST_CHECKED;
|
|
||||||
|
|
||||||
GetDlgItemTextW(hwndDlg, ID_EDT_URL, url, _countof(url));
|
GetDlgItemTextW(hwndDlg, ID_EDT_URL, url, _countof(url));
|
||||||
|
|
||||||
|
@ -504,7 +542,18 @@ ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa
|
||||||
GetDlgItemTextUtf8(hwndDlg, ID_EDT_AUTH_PASS, &password, &password_len);
|
GetDlgItemTextUtf8(hwndDlg, ID_EDT_AUTH_PASS, &password, &password_len);
|
||||||
|
|
||||||
WCHAR path[MAX_PATH + 1] = { 0 };
|
WCHAR path[MAX_PATH + 1] = { 0 };
|
||||||
BOOL downloaded = DownloadProfile(hwndDlg, url, username, password, autologin, path, _countof(path));
|
struct UrlComponents comps = {0};
|
||||||
|
if (type == server_as)
|
||||||
|
{
|
||||||
|
|
||||||
|
autologin = IsDlgButtonChecked(hwndDlg, ID_CHK_AUTOLOGIN) == BST_CHECKED;
|
||||||
|
GetASUrl(url, autologin, &comps);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ParseUrl(url, &comps);
|
||||||
|
}
|
||||||
|
BOOL downloaded = DownloadProfile(hwndDlg, &comps, username, password, path, _countof(path));
|
||||||
|
|
||||||
if (username_len != 0)
|
if (username_len != 0)
|
||||||
free(username);
|
free(username);
|
||||||
|
@ -540,5 +589,10 @@ ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa
|
||||||
|
|
||||||
void ImportConfigFromAS()
|
void ImportConfigFromAS()
|
||||||
{
|
{
|
||||||
LocalizedDialogBoxParam(ID_DLG_URL_PROFILE_IMPORT, ImportProfileFromURLDialogFunc, 0);
|
LocalizedDialogBoxParam(ID_DLG_URL_PROFILE_IMPORT, ImportProfileFromURLDialogFunc, (LPARAM) server_as);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImportConfigFromURL()
|
||||||
|
{
|
||||||
|
LocalizedDialogBoxParam(ID_DLG_URL_PROFILE_IMPORT, ImportProfileFromURLDialogFunc, (LPARAM) server_generic);
|
||||||
|
}
|
||||||
|
|
3
as.h
3
as.h
|
@ -19,4 +19,5 @@
|
||||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ImportConfigFromAS();
|
void ImportConfigFromAS();
|
||||||
|
void ImportConfigFromURL();
|
||||||
|
|
3
main.c
3
main.c
|
@ -559,6 +559,9 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
|
||||||
else if (LOWORD(wParam) == IDM_IMPORT_AS) {
|
else if (LOWORD(wParam) == IDM_IMPORT_AS) {
|
||||||
ImportConfigFromAS();
|
ImportConfigFromAS();
|
||||||
}
|
}
|
||||||
|
else if (LOWORD(wParam) == IDM_IMPORT_URL) {
|
||||||
|
ImportConfigFromURL();
|
||||||
|
}
|
||||||
else if (LOWORD(wParam) == IDM_SETTINGS) {
|
else if (LOWORD(wParam) == IDM_SETTINGS) {
|
||||||
ShowSettingsDialog();
|
ShowSettingsDialog();
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,7 @@
|
||||||
#define IDS_MENU_RECONNECT 1025
|
#define IDS_MENU_RECONNECT 1025
|
||||||
#define IDS_MENU_IMPORT_AS 1026
|
#define IDS_MENU_IMPORT_AS 1026
|
||||||
#define IDS_MENU_IMPORT_FILE 1027
|
#define IDS_MENU_IMPORT_FILE 1027
|
||||||
|
#define IDS_MENU_IMPORT_URL 1028
|
||||||
|
|
||||||
/* LogViewer Dialog */
|
/* LogViewer Dialog */
|
||||||
#define IDS_ERR_START_LOG_VIEWER 1101
|
#define IDS_ERR_START_LOG_VIEWER 1101
|
||||||
|
|
|
@ -264,14 +264,14 @@ BEGIN
|
||||||
END
|
END
|
||||||
|
|
||||||
/* URL Profile Import Dialog */
|
/* URL Profile Import Dialog */
|
||||||
ID_DLG_URL_PROFILE_IMPORT DIALOG 6, 18, 160, 95
|
ID_DLG_URL_PROFILE_IMPORT DIALOG 6, 18, 249, 95
|
||||||
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER | DS_SETFOREGROUND
|
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER | DS_SETFOREGROUND
|
||||||
CAPTION "Import Profile from Access Server"
|
CAPTION "Import Profile from Access Server"
|
||||||
FONT 8, "Microsoft Sans Serif"
|
FONT 8, "Microsoft Sans Serif"
|
||||||
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
||||||
BEGIN
|
BEGIN
|
||||||
LTEXT "U&RL:", 201, 6, 9, 50, 10
|
LTEXT "U&RL:", 201, 6, 9, 50, 10
|
||||||
EDITTEXT ID_EDT_URL, 60, 6, 94, 12, ES_AUTOHSCROLL
|
EDITTEXT ID_EDT_URL, 60, 6, 183, 12, ES_AUTOHSCROLL
|
||||||
LTEXT "&Username:", 202, 6, 26, 50, 10
|
LTEXT "&Username:", 202, 6, 26, 50, 10
|
||||||
EDITTEXT ID_EDT_AUTH_USER, 60, 23, 94, 12, ES_AUTOHSCROLL
|
EDITTEXT ID_EDT_AUTH_USER, 60, 23, 94, 12, ES_AUTOHSCROLL
|
||||||
LTEXT "&Password:", ID_LTEXT_PASSWORD, 6, 42, 50, 10
|
LTEXT "&Password:", ID_LTEXT_PASSWORD, 6, 42, 50, 10
|
||||||
|
@ -295,6 +295,7 @@ BEGIN
|
||||||
IDS_MENU_SERVICE "OpenVPN Service"
|
IDS_MENU_SERVICE "OpenVPN Service"
|
||||||
IDS_MENU_IMPORT "Import"
|
IDS_MENU_IMPORT "Import"
|
||||||
IDS_MENU_IMPORT_AS "Import from Access Server…"
|
IDS_MENU_IMPORT_AS "Import from Access Server…"
|
||||||
|
IDS_MENU_IMPORT_URL "Import from URL…"
|
||||||
IDS_MENU_IMPORT_FILE "Import file…"
|
IDS_MENU_IMPORT_FILE "Import file…"
|
||||||
IDS_MENU_SETTINGS "Settings…"
|
IDS_MENU_SETTINGS "Settings…"
|
||||||
IDS_MENU_CLOSE "Exit"
|
IDS_MENU_CLOSE "Exit"
|
||||||
|
|
2
tray.c
2
tray.c
|
@ -220,6 +220,7 @@ CreatePopupMenus()
|
||||||
AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuImport, LoadLocalizedString(IDS_MENU_IMPORT));
|
AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuImport, LoadLocalizedString(IDS_MENU_IMPORT));
|
||||||
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_FILE, LoadLocalizedString(IDS_MENU_IMPORT_FILE));
|
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_FILE, LoadLocalizedString(IDS_MENU_IMPORT_FILE));
|
||||||
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_AS, LoadLocalizedString(IDS_MENU_IMPORT_AS));
|
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_AS, LoadLocalizedString(IDS_MENU_IMPORT_AS));
|
||||||
|
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_URL, LoadLocalizedString(IDS_MENU_IMPORT_URL));
|
||||||
|
|
||||||
AppendMenu(hMenu, MF_STRING ,IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
|
AppendMenu(hMenu, MF_STRING ,IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
|
||||||
AppendMenu(hMenu, MF_STRING ,IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
|
AppendMenu(hMenu, MF_STRING ,IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
|
||||||
|
@ -280,6 +281,7 @@ CreatePopupMenus()
|
||||||
AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuImport, LoadLocalizedString(IDS_MENU_IMPORT));
|
AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuImport, LoadLocalizedString(IDS_MENU_IMPORT));
|
||||||
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_FILE, LoadLocalizedString(IDS_MENU_IMPORT_FILE));
|
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_FILE, LoadLocalizedString(IDS_MENU_IMPORT_FILE));
|
||||||
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_AS, LoadLocalizedString(IDS_MENU_IMPORT_AS));
|
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_AS, LoadLocalizedString(IDS_MENU_IMPORT_AS));
|
||||||
|
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_URL, LoadLocalizedString(IDS_MENU_IMPORT_URL));
|
||||||
|
|
||||||
AppendMenu(hMenu, MF_STRING, IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
|
AppendMenu(hMenu, MF_STRING, IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
|
||||||
AppendMenu(hMenu, MF_STRING, IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
|
AppendMenu(hMenu, MF_STRING, IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
|
||||||
|
|
1
tray.h
1
tray.h
|
@ -34,6 +34,7 @@
|
||||||
#define IDM_IMPORT 224
|
#define IDM_IMPORT 224
|
||||||
#define IDM_IMPORT_FILE 225
|
#define IDM_IMPORT_FILE 225
|
||||||
#define IDM_IMPORT_AS 226
|
#define IDM_IMPORT_AS 226
|
||||||
|
#define IDM_IMPORT_URL 227
|
||||||
|
|
||||||
#define IDM_CONNECTMENU 300
|
#define IDM_CONNECTMENU 300
|
||||||
#define IDM_DISCONNECTMENU (1 + IDM_CONNECTMENU)
|
#define IDM_DISCONNECTMENU (1 + IDM_CONNECTMENU)
|
||||||
|
|
Loading…
Reference in New Issue