Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9ba34373b | ||
|
|
4c49f1b736 | ||
|
|
b266bf42f5 | ||
|
|
2e7518d802 | ||
|
|
18e956f34c | ||
|
|
333ad2516f | ||
|
|
9ffcf77ab1 | ||
|
|
d0d6a3cdfa |
@@ -1,3 +1,8 @@
|
|||||||
|
3.4.3 2017-1-11
|
||||||
|
- Make the previous portable mode as default
|
||||||
|
- Refine networking by Noisyfox
|
||||||
|
- Bug fixes and improvements
|
||||||
|
|
||||||
3.4.2.1 2016-12-30
|
3.4.2.1 2016-12-30
|
||||||
- Refine Traditional Chinese translation by LNDDYL
|
- Refine Traditional Chinese translation by LNDDYL
|
||||||
- sysproxy: reduce false positives on virus detection
|
- sysproxy: reduce false positives on virus detection
|
||||||
|
|||||||
+19
-19
@@ -994,31 +994,31 @@ https://tls.mbed.org
|
|||||||
License: https://raw.githubusercontent.com/ARMmbed/mbedtls/master/LICENSE
|
License: https://raw.githubusercontent.com/ARMmbed/mbedtls/master/LICENSE
|
||||||
|
|
||||||
|
|
||||||
SimpleJson
|
Newtonsoft.Json
|
||||||
----------
|
----------
|
||||||
|
|
||||||
https://github.com/facebook-csharp-sdk/simple-json
|
https://raw.githubusercontent.com/JamesNK/Newtonsoft.Json/master/LICENSE.md
|
||||||
|
|
||||||
Copyright (c) 2011, The Outercurve Foundation
|
The MIT License (MIT)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Copyright (c) 2007 James Newton-King
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
included in all copies or substantial portions of the Software.
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
The above copyright notice and this permission notice shall be included in all
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
copies or substantial portions of the Software.
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
ZXing
|
ZXing
|
||||||
|
|||||||
@@ -89,11 +89,6 @@ if you want to deactivate all, please clear all textboxes.
|
|||||||
|
|
||||||
Please visit [Servers] for more information.
|
Please visit [Servers] for more information.
|
||||||
|
|
||||||
#### Portable Mode
|
|
||||||
|
|
||||||
If you want to put all temporary files into shadowsocks/temp folder instead of
|
|
||||||
system temp folder, create a `shadowsocks_portable_mode.txt` into shadowsocks folder.
|
|
||||||
|
|
||||||
#### Develop
|
#### Develop
|
||||||
|
|
||||||
[Visual Studio 2015] & [.NET Framework 4.6.2 Developer Pack] are required.
|
[Visual Studio 2015] & [.NET Framework 4.6.2 Developer Pack] are required.
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
using Shadowsocks.Properties;
|
using Shadowsocks.Properties;
|
||||||
|
|
||||||
public class I18N
|
public static class I18N
|
||||||
{
|
{
|
||||||
protected static Dictionary<string, string> Strings;
|
private static Dictionary<string, string> _strings = new Dictionary<string, string>();
|
||||||
|
|
||||||
static void Init(string res)
|
private static void Init(string res)
|
||||||
{
|
{
|
||||||
using (var sr = new StringReader(res))
|
using (var sr = new StringReader(res))
|
||||||
{
|
{
|
||||||
@@ -23,38 +23,28 @@ namespace Shadowsocks.Controller
|
|||||||
var pos = line.IndexOf('=');
|
var pos = line.IndexOf('=');
|
||||||
if (pos < 1)
|
if (pos < 1)
|
||||||
continue;
|
continue;
|
||||||
Strings[line.Substring(0, pos)] = line.Substring(pos + 1);
|
_strings[line.Substring(0, pos)] = line.Substring(pos + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static I18N()
|
static I18N()
|
||||||
{
|
{
|
||||||
Strings = new Dictionary<string, string>();
|
string name = CultureInfo.CurrentCulture.EnglishName;
|
||||||
string name = CultureInfo.CurrentCulture.Name;
|
if (name.StartsWith("Chinese", StringComparison.OrdinalIgnoreCase))
|
||||||
if (name.StartsWith("zh"))
|
|
||||||
{
|
{
|
||||||
if (name == "zh" || name == "zh-CN")
|
// choose Traditional Chinese only if we get explicit indication
|
||||||
{
|
Init(name.Contains("Traditional")
|
||||||
Init(Resources.cn);
|
? Resources.zh_tw
|
||||||
}
|
: Resources.cn);
|
||||||
else
|
|
||||||
{
|
|
||||||
Init(Resources.zh_tw);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetString(string key)
|
public static string GetString(string key)
|
||||||
{
|
{
|
||||||
if (Strings.ContainsKey(key))
|
return _strings.ContainsKey(key)
|
||||||
{
|
? _strings[key]
|
||||||
return Strings[key];
|
: key;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,21 +121,13 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Utils.IsPortableMode())
|
/*
|
||||||
{
|
* Under PortableMode, we could identify it by the path of ss_privoxy.exe.
|
||||||
/*
|
*/
|
||||||
* Under PortableMode, we could identify it by the path of ss_privoxy.exe.
|
var path = process.MainModule.FileName;
|
||||||
*/
|
|
||||||
var path = process.MainModule.FileName;
|
|
||||||
|
|
||||||
return Utils.GetTempPath("ss_privoxy.exe").Equals(path);
|
return Utils.GetTempPath("ss_privoxy.exe").Equals(path);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var cmd = process.GetCommandLine();
|
|
||||||
|
|
||||||
return cmd.Contains(_uniqueConfigFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -322,24 +322,15 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int atyp = _connetionRecvBuffer[3];
|
if (_command == 1)
|
||||||
|
|
||||||
switch (atyp)
|
|
||||||
{
|
{
|
||||||
case 1: // IPv4 address, 4 bytes
|
byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
|
||||||
ReadAddress(4 + 2 - 1);
|
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
|
||||||
break;
|
new AsyncCallback(ResponseCallback), null);
|
||||||
case 3: // domain name, length + str
|
}
|
||||||
int len = _connetionRecvBuffer[4];
|
else if (_command == 3)
|
||||||
ReadAddress(len + 2);
|
{
|
||||||
break;
|
ReadAddress(HandleUDPAssociate);
|
||||||
case 4: // IPv6 address, 16 bytes
|
|
||||||
ReadAddress(16 + 2 - 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Logging.Debug("Unsupported ATYP=" + atyp);
|
|
||||||
Close();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,12 +347,50 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadAddress(int bytesRemain)
|
private void ResponseCallback(IAsyncResult ar)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_connection.EndSend(ar);
|
||||||
|
|
||||||
|
ReadAddress(StartConnect);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logging.LogUsefulException(e);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadAddress(Action onSuccess)
|
||||||
|
{
|
||||||
|
int atyp = _connetionRecvBuffer[3];
|
||||||
|
|
||||||
|
switch (atyp)
|
||||||
|
{
|
||||||
|
case 1: // IPv4 address, 4 bytes
|
||||||
|
ReadAddress(4 + 2 - 1, onSuccess);
|
||||||
|
break;
|
||||||
|
case 3: // domain name, length + str
|
||||||
|
int len = _connetionRecvBuffer[4];
|
||||||
|
ReadAddress(len + 2, onSuccess);
|
||||||
|
break;
|
||||||
|
case 4: // IPv6 address, 16 bytes
|
||||||
|
ReadAddress(16 + 2 - 1, onSuccess);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logging.Debug("Unsupported ATYP=" + atyp);
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadAddress(int bytesRemain, Action onSuccess)
|
||||||
{
|
{
|
||||||
Array.Copy(_connetionRecvBuffer, 3, _connetionRecvBuffer, 0, 2);
|
Array.Copy(_connetionRecvBuffer, 3, _connetionRecvBuffer, 0, 2);
|
||||||
|
|
||||||
// Read the remain address bytes
|
// Read the remain address bytes
|
||||||
_connection.BeginReceive(_connetionRecvBuffer, 2, RecvSize - 2, SocketFlags.None, OnAddressFullyRead, bytesRemain);
|
_connection.BeginReceive(_connetionRecvBuffer, 2, RecvSize - 2, SocketFlags.None, OnAddressFullyRead, new object[] {bytesRemain, onSuccess});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAddressFullyRead(IAsyncResult ar)
|
private void OnAddressFullyRead(IAsyncResult ar)
|
||||||
@@ -370,7 +399,12 @@ namespace Shadowsocks.Controller
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
int bytesRead = _connection.EndReceive(ar);
|
int bytesRead = _connection.EndReceive(ar);
|
||||||
int bytesRemain = (int) ar.AsyncState;
|
|
||||||
|
var states = (object[]) ar.AsyncState;
|
||||||
|
|
||||||
|
int bytesRemain = (int)states[0];
|
||||||
|
var onSuccess = (Action) states[1];
|
||||||
|
|
||||||
if (bytesRead >= bytesRemain)
|
if (bytesRead >= bytesRemain)
|
||||||
{
|
{
|
||||||
_firstPacketLength = bytesRead + 2;
|
_firstPacketLength = bytesRead + 2;
|
||||||
@@ -405,16 +439,7 @@ namespace Shadowsocks.Controller
|
|||||||
|
|
||||||
_destEndPoint = SocketUtil.GetEndPoint(dst_addr, dst_port);
|
_destEndPoint = SocketUtil.GetEndPoint(dst_addr, dst_port);
|
||||||
|
|
||||||
if (_command == 1)
|
onSuccess.Invoke();
|
||||||
{
|
|
||||||
byte[] response = {5, 0, 0, 1, 0, 0, 0, 0, 0, 0};
|
|
||||||
_connection.BeginSend(response, 0, response.Length, SocketFlags.None,
|
|
||||||
new AsyncCallback(ResponseCallback), null);
|
|
||||||
}
|
|
||||||
else if (_command == 3)
|
|
||||||
{
|
|
||||||
HandleUDPAssociate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -479,20 +504,6 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResponseCallback(IAsyncResult ar)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_connection.EndSend(ar);
|
|
||||||
StartConnect();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logging.LogUsefulException(e);
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// inner class
|
// inner class
|
||||||
private class ProxyTimer : Timer
|
private class ProxyTimer : Timer
|
||||||
{
|
{
|
||||||
@@ -716,6 +727,26 @@ namespace Shadowsocks.Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private static readonly Random Rnd = new Random();
|
||||||
|
|
||||||
|
private void TryReadAvailableData()
|
||||||
|
{
|
||||||
|
int available = Math.Min(_connection.Available, RecvSize - _firstPacketLength);
|
||||||
|
if (available > 0)
|
||||||
|
{
|
||||||
|
// Pick a random chunk size, or is it truly necessary? Random packet size is some sort of 'characteristic' itself.
|
||||||
|
//lock (Rnd)
|
||||||
|
//{
|
||||||
|
// available = Rnd.Next(available + 1);
|
||||||
|
//}
|
||||||
|
|
||||||
|
var size = _connection.Receive(_connetionRecvBuffer, _firstPacketLength, available,
|
||||||
|
SocketFlags.None);
|
||||||
|
|
||||||
|
_firstPacketLength += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void StartPipe(AsyncSession session)
|
private void StartPipe(AsyncSession session)
|
||||||
{
|
{
|
||||||
if (_closed) return;
|
if (_closed) return;
|
||||||
@@ -723,6 +754,9 @@ namespace Shadowsocks.Controller
|
|||||||
{
|
{
|
||||||
_startReceivingTime = DateTime.Now;
|
_startReceivingTime = DateTime.Now;
|
||||||
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
|
session.Remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(PipeRemoteReceiveCallback), session);
|
||||||
|
|
||||||
|
TryReadAvailableData();
|
||||||
|
Logging.Debug($"_firstPacketLength = {_firstPacketLength}");
|
||||||
SendToServer(_firstPacketLength, session);
|
SendToServer(_firstPacketLength, session);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Shadowsocks.Controller
|
|||||||
public string LatestVersionLocalName;
|
public string LatestVersionLocalName;
|
||||||
public event EventHandler CheckUpdateCompleted;
|
public event EventHandler CheckUpdateCompleted;
|
||||||
|
|
||||||
public const string Version = "3.4.2.1";
|
public const string Version = "3.4.3";
|
||||||
|
|
||||||
private class CheckUpdateTimer : System.Timers.Timer
|
private class CheckUpdateTimer : System.Timers.Timer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ Check for Updates at Startup=启动时检查更新
|
|||||||
Check Pre-release Version=检查测试版更新
|
Check Pre-release Version=检查测试版更新
|
||||||
Edit Hotkeys...=编辑快捷键...
|
Edit Hotkeys...=编辑快捷键...
|
||||||
About...=关于...
|
About...=关于...
|
||||||
|
Help=帮助
|
||||||
Quit=退出
|
Quit=退出
|
||||||
Edit Servers=编辑服务器
|
Edit Servers=编辑服务器
|
||||||
Load Balance=负载均衡
|
Load Balance=负载均衡
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ Check for Updates at Startup=啟動時檢查更新
|
|||||||
Check Pre-release Version=檢查發行前版本更新
|
Check Pre-release Version=檢查發行前版本更新
|
||||||
Edit Hotkeys...=編輯快速鍵...
|
Edit Hotkeys...=編輯快速鍵...
|
||||||
About...=關於...
|
About...=關於...
|
||||||
|
Help=幫助
|
||||||
Quit=結束
|
Quit=結束
|
||||||
Edit Servers=編輯伺服器
|
Edit Servers=編輯伺服器
|
||||||
Load Balance=負載平衡
|
Load Balance=負載平衡
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("Shadowsocks")]
|
[assembly: AssemblyProduct("Shadowsocks")]
|
||||||
[assembly: AssemblyCopyright("clowwindy and community 2016")]
|
[assembly: AssemblyCopyright("clowwindy & community 2017")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
|||||||
@@ -25,43 +25,26 @@ namespace Shadowsocks.Util
|
|||||||
|
|
||||||
public static class Utils
|
public static class Utils
|
||||||
{
|
{
|
||||||
private static bool? _portableMode;
|
private static string _tempPath = null;
|
||||||
private static string TempPath = null;
|
|
||||||
|
|
||||||
public static bool IsPortableMode()
|
|
||||||
{
|
|
||||||
if (!_portableMode.HasValue)
|
|
||||||
{
|
|
||||||
_portableMode = File.Exists(Path.Combine(Application.StartupPath, "shadowsocks_portable_mode.txt"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _portableMode.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return path to store temporary files
|
// return path to store temporary files
|
||||||
public static string GetTempPath()
|
public static string GetTempPath()
|
||||||
{
|
{
|
||||||
if (TempPath == null)
|
if (_tempPath == null)
|
||||||
{
|
{
|
||||||
if (IsPortableMode())
|
try
|
||||||
try
|
{
|
||||||
{
|
Directory.CreateDirectory(Path.Combine(Application.StartupPath, "ss_win_temp"));
|
||||||
Directory.CreateDirectory(Path.Combine(Application.StartupPath, "temp"));
|
// don't use "/", it will fail when we call explorer /select xxx/ss_win_temp\xxx.log
|
||||||
}
|
_tempPath = Path.Combine(Application.StartupPath, "ss_win_temp");
|
||||||
catch (Exception e)
|
}
|
||||||
{
|
catch (Exception e)
|
||||||
TempPath = Path.GetTempPath();
|
{
|
||||||
Logging.LogUsefulException(e);
|
Logging.Error(e);
|
||||||
}
|
throw;
|
||||||
finally
|
}
|
||||||
{
|
|
||||||
// don't use "/", it will fail when we call explorer /select xxx/temp\xxx.log
|
|
||||||
TempPath = Path.Combine(Application.StartupPath, "temp");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
TempPath = Path.GetTempPath();
|
|
||||||
}
|
}
|
||||||
return TempPath;
|
return _tempPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return a full path with filename combined which pointed to the temporary directory
|
// return a full path with filename combined which pointed to the temporary directory
|
||||||
|
|||||||
@@ -197,11 +197,16 @@ namespace Shadowsocks.View
|
|||||||
for (int y = 0; y < iconCopy.Height; y++)
|
for (int y = 0; y < iconCopy.Height; y++)
|
||||||
{
|
{
|
||||||
Color color = originIcon.GetPixel(x, y);
|
Color color = originIcon.GetPixel(x, y);
|
||||||
if (color.A != 0 && color.R > 30)
|
if (color.A != 0)
|
||||||
{
|
{
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
{
|
{
|
||||||
iconCopy.SetPixel(x, y, Color.FromArgb((byte)(color.A / 1.25), color.R, color.G, color.B));
|
Color flyBlue = Color.FromArgb(192, 192, 192);
|
||||||
|
// Multiply with flyBlue
|
||||||
|
int red = color.R * flyBlue.R / 255;
|
||||||
|
int green = color.G * flyBlue.G / 255;
|
||||||
|
int blue = color.B * flyBlue.B / 255;
|
||||||
|
iconCopy.SetPixel(x, y, Color.FromArgb(color.A, red, green, blue));
|
||||||
}
|
}
|
||||||
else if (global)
|
else if (global)
|
||||||
{
|
{
|
||||||
@@ -282,16 +287,18 @@ namespace Shadowsocks.View
|
|||||||
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
|
this.AutoStartupItem = CreateMenuItem("Start on Boot", new EventHandler(this.AutoStartupItem_Click)),
|
||||||
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
|
this.ShareOverLANItem = CreateMenuItem("Allow Clients from LAN", new EventHandler(this.ShareOverLANItem_Click)),
|
||||||
new MenuItem("-"),
|
new MenuItem("-"),
|
||||||
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
|
|
||||||
this.VerboseLoggingToggleItem = CreateMenuItem( "Verbose Logging", new EventHandler(this.VerboseLoggingToggleItem_Click) ),
|
|
||||||
this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)),
|
this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)),
|
||||||
CreateMenuGroup("Updates...", new MenuItem[] {
|
CreateMenuGroup("Help", new MenuItem[] {
|
||||||
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)),
|
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)),
|
||||||
new MenuItem("-"),
|
this.VerboseLoggingToggleItem = CreateMenuItem( "Verbose Logging", new EventHandler(this.VerboseLoggingToggleItem_Click) ),
|
||||||
this.autoCheckUpdatesToggleItem = CreateMenuItem("Check for Updates at Startup", new EventHandler(this.autoCheckUpdatesToggleItem_Click)),
|
CreateMenuGroup("Updates...", new MenuItem[] {
|
||||||
this.checkPreReleaseToggleItem = CreateMenuItem("Check Pre-release Version", new EventHandler(this.checkPreReleaseToggleItem_Click)),
|
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)),
|
||||||
|
new MenuItem("-"),
|
||||||
|
this.autoCheckUpdatesToggleItem = CreateMenuItem("Check for Updates at Startup", new EventHandler(this.autoCheckUpdatesToggleItem_Click)),
|
||||||
|
this.checkPreReleaseToggleItem = CreateMenuItem("Check Pre-release Version", new EventHandler(this.checkPreReleaseToggleItem_Click)),
|
||||||
|
}),
|
||||||
|
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)),
|
||||||
}),
|
}),
|
||||||
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)),
|
|
||||||
new MenuItem("-"),
|
new MenuItem("-"),
|
||||||
CreateMenuItem("Quit", new EventHandler(this.Quit_Click))
|
CreateMenuItem("Quit", new EventHandler(this.Quit_Click))
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user