@@ -16,11 +16,11 @@ namespace Shadowsocks.PAC | |||||
public const string USER_RULE_FILE = "user-rule.txt"; | public const string USER_RULE_FILE = "user-rule.txt"; | ||||
public const string USER_ABP_FILE = "abp.txt"; | public const string USER_ABP_FILE = "abp.txt"; | ||||
FileSystemWatcher PACFileWatcher; | |||||
FileSystemWatcher UserRuleFileWatcher; | |||||
FileSystemWatcher? PACFileWatcher; | |||||
FileSystemWatcher? UserRuleFileWatcher; | |||||
public event EventHandler PACFileChanged; | |||||
public event EventHandler UserRuleFileChanged; | |||||
public event EventHandler? PACFileChanged; | |||||
public event EventHandler? UserRuleFileChanged; | |||||
private PACSettings _PACSettings; | private PACSettings _PACSettings; | ||||
private GeositeUpdater _geositeUpdater; | private GeositeUpdater _geositeUpdater; | ||||
@@ -124,7 +124,7 @@ namespace Shadowsocks.PAC | |||||
{ | { | ||||
if (kv[0] == "Host") | if (kv[0] == "Host") | ||||
{ | { | ||||
if (kv[1].Trim() == ((IPEndPoint)socket.LocalEndPoint).ToString()) | |||||
if (kv[1].Trim() == (socket.LocalEndPoint as IPEndPoint)?.ToString()) | |||||
{ | { | ||||
hostMatch = true; | hostMatch = true; | ||||
} | } | ||||
@@ -164,7 +164,7 @@ namespace Shadowsocks.PAC | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
IPEndPoint localEndPoint = (IPEndPoint)socket.LocalEndPoint; | |||||
IPEndPoint localEndPoint = socket.LocalEndPoint as IPEndPoint ?? throw new ArgumentException("Invalid socket local endpoint.", nameof(socket)); | |||||
string proxy = GetPACAddress(localEndPoint, useSocks); | string proxy = GetPACAddress(localEndPoint, useSocks); | ||||
@@ -5,7 +5,7 @@ namespace Shadowsocks.WPF.Localization | |||||
{ | { | ||||
public class LocalizationProvider | public class LocalizationProvider | ||||
{ | { | ||||
private static readonly string CallingAssemblyName = Assembly.GetCallingAssembly().GetName().Name; | |||||
private static readonly string CallingAssemblyName = Assembly.GetCallingAssembly().GetName().Name ?? "Shadowsocks.WPF"; | |||||
public static T GetLocalizedValue<T>(string key) => LocExtension.GetLocalizedValue<T>($"{CallingAssemblyName}:Strings:{key}"); | public static T GetLocalizedValue<T>(string key) => LocExtension.GetLocalizedValue<T>($"{CallingAssemblyName}:Strings:{key}"); | ||||
} | } | ||||
@@ -6,6 +6,7 @@ using System.Net.Sockets; | |||||
namespace Shadowsocks.WPF.Services | namespace Shadowsocks.WPF.Services | ||||
{ | { | ||||
#nullable disable | |||||
public class PortForwarder : StreamService | public class PortForwarder : StreamService | ||||
{ | { | ||||
private readonly int _targetPort; | private readonly int _targetPort; | ||||
@@ -12,7 +12,7 @@ namespace Shadowsocks.WPF.Services | |||||
// https://github.com/shadowsocks/shadowsocks-org/wiki/Plugin | // https://github.com/shadowsocks/shadowsocks-org/wiki/Plugin | ||||
public sealed class Sip003Plugin : IDisposable | public sealed class Sip003Plugin : IDisposable | ||||
{ | { | ||||
public IPEndPoint LocalEndPoint { get; private set; } | |||||
public IPEndPoint? LocalEndPoint { get; private set; } | |||||
public int ProcessId => _started ? _pluginProcess.Id : 0; | public int ProcessId => _started ? _pluginProcess.Id : 0; | ||||
private readonly object _startProcessLock = new object(); | private readonly object _startProcessLock = new object(); | ||||
@@ -20,7 +20,7 @@ namespace Shadowsocks.WPF.Services | |||||
private bool _started; | private bool _started; | ||||
private bool _disposed; | private bool _disposed; | ||||
public static Sip003Plugin CreateIfConfigured(Server server, bool showPluginOutput) | |||||
public static Sip003Plugin? CreateIfConfigured(Server server, bool showPluginOutput) | |||||
{ | { | ||||
if (server == null) | if (server == null) | ||||
{ | { | ||||
@@ -119,7 +119,7 @@ namespace Shadowsocks.WPF.Services | |||||
return true; | return true; | ||||
} | } | ||||
public string ExpandEnvironmentVariables(string name, StringDictionary environmentVariables = null) | |||||
public string ExpandEnvironmentVariables(string name, StringDictionary? environmentVariables = null) | |||||
{ | { | ||||
// Expand the environment variables from the new process itself | // Expand the environment variables from the new process itself | ||||
if (environmentVariables != null) | if (environmentVariables != null) | ||||
@@ -42,7 +42,7 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
// pointer to full path and file name of phone-book file | // pointer to full path and file name of phone-book file | ||||
string lpszPhonebook, | string lpszPhonebook, | ||||
// buffer to receive phone-book entries | // buffer to receive phone-book entries | ||||
[In, Out] RasEntryName[] lprasentryname, | |||||
[In, Out] RasEntryName[]? lprasentryname, | |||||
// size in bytes of buffer | // size in bytes of buffer | ||||
ref int lpcb, | ref int lpcb, | ||||
// number of entries written to buffer | // number of entries written to buffer | ||||
@@ -55,14 +55,14 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
int entryNameSize = 0; | int entryNameSize = 0; | ||||
int lpSize = 0; | int lpSize = 0; | ||||
uint retval = ESuccess; | uint retval = ESuccess; | ||||
RasEntryName[] names = null; | |||||
RasEntryName[] names = Array.Empty<RasEntryName>(); | |||||
entryNameSize = Marshal.SizeOf(typeof(RasEntryName)); | entryNameSize = Marshal.SizeOf(typeof(RasEntryName)); | ||||
// Windows Vista or later: To determine the required buffer size, call RasEnumEntries | // Windows Vista or later: To determine the required buffer size, call RasEnumEntries | ||||
// with lprasentryname set to NULL. The variable pointed to by lpcb should be set to zero. | // with lprasentryname set to NULL. The variable pointed to by lpcb should be set to zero. | ||||
// The function will return the required buffer size in lpcb and an error code of ERROR_BUFFER_TOO_SMALL. | // The function will return the required buffer size in lpcb and an error code of ERROR_BUFFER_TOO_SMALL. | ||||
retval = RasEnumEntries(null, null, null, ref lpSize, out lpNames); | |||||
retval = RasEnumEntries("", "", null, ref lpSize, out lpNames); | |||||
if (retval == EBufferTooSmall) | if (retval == EBufferTooSmall) | ||||
{ | { | ||||
names = new RasEntryName[lpNames]; | names = new RasEntryName[lpNames]; | ||||
@@ -71,7 +71,7 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
names[i].dwSize = entryNameSize; | names[i].dwSize = entryNameSize; | ||||
} | } | ||||
retval = RasEnumEntries(null, null, names, ref lpSize, out lpNames); | |||||
retval = RasEnumEntries("", "", names, ref lpSize, out lpNames); | |||||
} | } | ||||
if (retval == ESuccess) | if (retval == ESuccess) | ||||
@@ -136,7 +136,7 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
Record(); | |||||
initialSetting = Query(); | |||||
} | } | ||||
catch (DllNotFoundException) | catch (DllNotFoundException) | ||||
{ | { | ||||
@@ -153,9 +153,14 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
throw we; | |||||
throw; | |||||
} | } | ||||
} | } | ||||
finally | |||||
{ | |||||
if (initialSetting == null) | |||||
initialSetting = new(); | |||||
} | |||||
} | } | ||||
public static void ProxyGlobal(string server, string bypass) | public static void ProxyGlobal(string server, string bypass) | ||||
@@ -188,11 +193,6 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
Exec(options); | Exec(options); | ||||
} | } | ||||
private static void Record() | |||||
{ | |||||
initialSetting ??= Query(); | |||||
} | |||||
public static void Restore() | public static void Restore() | ||||
{ | { | ||||
Set(initialSetting); | Set(initialSetting); | ||||
@@ -231,7 +231,7 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
new InternetPerConnectionOption{dwOption = (int)InternetPerConnectionOptionEnum.AutoConfigUrl}, | new InternetPerConnectionOption{dwOption = (int)InternetPerConnectionOptionEnum.AutoConfigUrl}, | ||||
}; | }; | ||||
(IntPtr unmanagedList, int listSize) = PrepareOptionList(options, null); | |||||
(IntPtr unmanagedList, int listSize) = PrepareOptionList(options, ""); | |||||
bool ok = InternetQueryOption(IntPtr.Zero, (int)InternetOptions.PerConnectionOption, unmanagedList, ref listSize); | bool ok = InternetQueryOption(IntPtr.Zero, (int)InternetOptions.PerConnectionOption, unmanagedList, ref listSize); | ||||
if (!ok) | if (!ok) | ||||
{ | { | ||||
@@ -260,13 +260,13 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
proxy.Flags = (InternetPerConnectionFlags)o.Value.dwValue; | proxy.Flags = (InternetPerConnectionFlags)o.Value.dwValue; | ||||
break; | break; | ||||
case InternetPerConnectionOptionEnum.AutoConfigUrl: | case InternetPerConnectionOptionEnum.AutoConfigUrl: | ||||
proxy.AutoConfigUrl = Marshal.PtrToStringAuto(o.Value.pszValue); | |||||
proxy.AutoConfigUrl = Marshal.PtrToStringAuto(o.Value.pszValue) ?? ""; | |||||
break; | break; | ||||
case InternetPerConnectionOptionEnum.ProxyBypass: | case InternetPerConnectionOptionEnum.ProxyBypass: | ||||
proxy.ProxyBypass = Marshal.PtrToStringAuto(o.Value.pszValue); | |||||
proxy.ProxyBypass = Marshal.PtrToStringAuto(o.Value.pszValue) ?? ""; | |||||
break; | break; | ||||
case InternetPerConnectionOptionEnum.ProxyServer: | case InternetPerConnectionOptionEnum.ProxyServer: | ||||
proxy.ProxyServer = Marshal.PtrToStringAuto(o.Value.pszValue); | |||||
proxy.ProxyServer = Marshal.PtrToStringAuto(o.Value.pszValue) ?? ""; | |||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
@@ -343,7 +343,7 @@ namespace Shadowsocks.WPF.Services.SystemProxy | |||||
private static void Exec(List<InternetPerConnectionOption> options) | private static void Exec(List<InternetPerConnectionOption> options) | ||||
{ | { | ||||
Exec(options, null); | |||||
Exec(options, ""); | |||||
foreach (string conn in RAS.GetAllConnections()) | foreach (string conn in RAS.GetAllConnections()) | ||||
{ | { | ||||
Exec(options, conn); | Exec(options, conn); | ||||
@@ -15,7 +15,7 @@ namespace Shadowsocks.WPF.Utils | |||||
public static bool Set(bool enabled) | public static bool Set(bool enabled) | ||||
{ | { | ||||
RegistryKey runKey = null; | |||||
RegistryKey? runKey = null; | |||||
try | try | ||||
{ | { | ||||
runKey = Registry.CurrentUser.CreateSubKey(registryRunKey, RegistryKeyPermissionCheck.ReadWriteSubTree); | runKey = Registry.CurrentUser.CreateSubKey(registryRunKey, RegistryKeyPermissionCheck.ReadWriteSubTree); | ||||
@@ -26,7 +26,7 @@ namespace Shadowsocks.WPF.Utils | |||||
} | } | ||||
if (enabled) | if (enabled) | ||||
{ | { | ||||
runKey.SetValue(Key, Process.GetCurrentProcess().MainModule?.FileName); | |||||
runKey.SetValue(Key, Utilities.ExecutablePath); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -60,7 +60,7 @@ namespace Shadowsocks.WPF.Utils | |||||
public static bool Check() | public static bool Check() | ||||
{ | { | ||||
RegistryKey runKey = null; | |||||
RegistryKey? runKey = null; | |||||
try | try | ||||
{ | { | ||||
runKey = Registry.CurrentUser.CreateSubKey(registryRunKey, RegistryKeyPermissionCheck.ReadWriteSubTree); | runKey = Registry.CurrentUser.CreateSubKey(registryRunKey, RegistryKeyPermissionCheck.ReadWriteSubTree); | ||||
@@ -78,7 +78,7 @@ namespace Shadowsocks.WPF.Utils | |||||
continue; | continue; | ||||
} | } | ||||
// Remove other startup keys with the same executable path. fixes #3011 and also assures compatibility with older versions | // Remove other startup keys with the same executable path. fixes #3011 and also assures compatibility with older versions | ||||
if (Utilities.ExecutablePath.Equals(runKey.GetValue(valueName).ToString(), StringComparison.InvariantCultureIgnoreCase) | |||||
if (Utilities.ExecutablePath.Equals(runKey.GetValue(valueName)?.ToString(), StringComparison.InvariantCultureIgnoreCase) | |||||
is bool matchedDuplicate && matchedDuplicate) | is bool matchedDuplicate && matchedDuplicate) | ||||
{ | { | ||||
runKey.DeleteValue(valueName); | runKey.DeleteValue(valueName); | ||||
@@ -59,7 +59,7 @@ namespace Shadowsocks.WPF.Utils | |||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
LogHost.Default.Error(ex, ""); | LogHost.Default.Error(ex, ""); | ||||
throw ex; | |||||
throw; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -21,7 +21,7 @@ namespace Shadowsocks.WPF.Utils | |||||
private const int OP_OPEN_URL = 1; | private const int OP_OPEN_URL = 1; | ||||
private static readonly string PIPE_PATH = $"Shadowsocks\\{Utilities.ExecutablePath.GetHashCode()}"; | private static readonly string PIPE_PATH = $"Shadowsocks\\{Utilities.ExecutablePath.GetHashCode()}"; | ||||
public event EventHandler<RequestAddUrlEventArgs> OpenUrlRequested; | |||||
public event EventHandler<RequestAddUrlEventArgs>? OpenUrlRequested; | |||||
public async void RunServer() | public async void RunServer() | ||||
{ | { | ||||
@@ -10,7 +10,7 @@ namespace Shadowsocks.WPF.Utils | |||||
public static bool Set(bool enabled) | public static bool Set(bool enabled) | ||||
{ | { | ||||
RegistryKey ssURLAssociation = null; | |||||
RegistryKey? ssURLAssociation = null; | |||||
try | try | ||||
{ | { | ||||
@@ -59,7 +59,7 @@ namespace Shadowsocks.WPF.Utils | |||||
public static bool Check() | public static bool Check() | ||||
{ | { | ||||
RegistryKey ssURLAssociation = null; | |||||
RegistryKey? ssURLAssociation = null; | |||||
try | try | ||||
{ | { | ||||
ssURLAssociation = Registry.CurrentUser.OpenSubKey(ssURLRegKey, true); | ssURLAssociation = Registry.CurrentUser.OpenSubKey(ssURLRegKey, true); | ||||
@@ -69,8 +69,8 @@ namespace Shadowsocks.WPF.Utils | |||||
return false; | return false; | ||||
} | } | ||||
var shellOpen = ssURLAssociation.OpenSubKey("shell").OpenSubKey("open").OpenSubKey("command"); | |||||
return (string)shellOpen.GetValue("") == $"{Utilities.ExecutablePath} --open-url %1"; | |||||
var shellOpen = ssURLAssociation.OpenSubKey("shell")?.OpenSubKey("open")?.OpenSubKey("command"); | |||||
return shellOpen?.GetValue("") as string == $"{Utilities.ExecutablePath} --open-url %1"; | |||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
{ | { | ||||
@@ -32,7 +32,7 @@ namespace Shadowsocks.WPF.Views | |||||
view => view.urlTextBox.Text) | view => view.urlTextBox.Text) | ||||
.DisposeWith(disposables); | .DisposeWith(disposables); | ||||
this.BindCommand(ViewModel, | |||||
this.BindCommand(ViewModel!, | |||||
viewModel => viewModel.CopyLink, | viewModel => viewModel.CopyLink, | ||||
view => view.copyLinkButton) | view => view.copyLinkButton) | ||||
.DisposeWith(disposables); | .DisposeWith(disposables); | ||||
@@ -21,15 +21,15 @@ namespace Shadowsocks.WPF.Views | |||||
view => releaseNotesMarkdownScrollViewer.Markdown) | view => releaseNotesMarkdownScrollViewer.Markdown) | ||||
.DisposeWith(disposables);*/ | .DisposeWith(disposables);*/ | ||||
this.BindCommand(ViewModel, | |||||
this.BindCommand(ViewModel!, | |||||
viewModel => viewModel.Update, | viewModel => viewModel.Update, | ||||
view => view.updateButton) | view => view.updateButton) | ||||
.DisposeWith(disposables); | .DisposeWith(disposables); | ||||
this.BindCommand(ViewModel, | |||||
this.BindCommand(ViewModel!, | |||||
viewModel => viewModel.SkipVersion, | viewModel => viewModel.SkipVersion, | ||||
view => view.skipVersionButton) | view => view.skipVersionButton) | ||||
.DisposeWith(disposables); | .DisposeWith(disposables); | ||||
this.BindCommand(ViewModel, | |||||
this.BindCommand(ViewModel!, | |||||
viewModel => viewModel.NotNow, | viewModel => viewModel.NotNow, | ||||
view => view.notNowButton) | view => view.notNowButton) | ||||
.DisposeWith(disposables); | .DisposeWith(disposables); | ||||