GetTempPath() now supports: return a full path with filename combined which pointed to the temporary directory
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
using Shadowsocks.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
@@ -15,8 +15,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
string temppath = Utils.GetTempPath();
|
||||
LogFile = Path.Combine(temppath, "shadowsocks.log");
|
||||
LogFile = Utils.GetTempPath("shadowsocks.log");
|
||||
FileStream fs = new FileStream(LogFile, FileMode.Append);
|
||||
StreamWriterWithTimestamp sw = new StreamWriterWithTimestamp(fs);
|
||||
sw.AutoFlush = true;
|
||||
@@ -34,7 +33,7 @@ namespace Shadowsocks.Controller
|
||||
|
||||
public static void Error(object o)
|
||||
{
|
||||
Console.WriteLine("[E] "+ o);
|
||||
Console.WriteLine("[E] " + o);
|
||||
}
|
||||
|
||||
public static void Info(object o)
|
||||
@@ -49,6 +48,25 @@ namespace Shadowsocks.Controller
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public static void Debug(EndPoint local, EndPoint remote, int len, string header = null, string tailer = null)
|
||||
{
|
||||
if (header == null && tailer == null)
|
||||
Debug($"{local} => {remote} (size={len})");
|
||||
else if (header == null && tailer != null)
|
||||
Debug($"{local} => {remote} (size={len}), {tailer}");
|
||||
else if (header != null && tailer == null)
|
||||
Debug($"{header}: {local} => {remote} (size={len})");
|
||||
else
|
||||
Debug($"{header}: {local} => {remote} (size={len}), {tailer}");
|
||||
}
|
||||
|
||||
public static void Debug(Socket sock, int len, string header = null, string tailer = null)
|
||||
{
|
||||
Debug(sock.LocalEndPoint, sock.RemoteEndPoint, len, header, tailer);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void LogUsefulException(Exception e)
|
||||
{
|
||||
// just log useful exceptions, not all of them
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
@@ -30,8 +31,8 @@ namespace Shadowsocks.Controller
|
||||
public Statistics FilteredStatistics { get; private set; }
|
||||
public static readonly DateTime UnknownDateTime = new DateTime(1970, 1, 1);
|
||||
private int Repeat => _config.RepeatTimesNum;
|
||||
private const int RetryInterval = 2*60*1000; //retry 2 minutes after failed
|
||||
private int Interval => (int) TimeSpan.FromMinutes(_config.DataCollectionMinutes).TotalMilliseconds;
|
||||
private const int RetryInterval = 2 * 60 * 1000; //retry 2 minutes after failed
|
||||
private int Interval => (int)TimeSpan.FromMinutes(_config.DataCollectionMinutes).TotalMilliseconds;
|
||||
private Timer _timer;
|
||||
private State _state;
|
||||
private List<Server> _servers;
|
||||
@@ -42,8 +43,7 @@ namespace Shadowsocks.Controller
|
||||
//static constructor to initialize every public static fields before refereced
|
||||
static AvailabilityStatistics()
|
||||
{
|
||||
var temppath = Utils.GetTempPath();
|
||||
AvailabilityStatisticsFile = Path.Combine(temppath, StatisticsFilesName);
|
||||
AvailabilityStatisticsFile = Utils.GetTempPath(StatisticsFilesName);
|
||||
}
|
||||
|
||||
public AvailabilityStatistics(Configuration config, StatisticsStrategyConfiguration statisticsConfig)
|
||||
@@ -181,11 +181,11 @@ namespace Shadowsocks.Controller
|
||||
if (!File.Exists(AvailabilityStatisticsFile))
|
||||
{
|
||||
var headerLine = string.Join(Delimiter, data.Select(kv => kv.Key).ToArray());
|
||||
lines = new[] {headerLine, dataLine};
|
||||
lines = new[] { headerLine, dataLine };
|
||||
}
|
||||
else
|
||||
{
|
||||
lines = new[] {dataLine};
|
||||
lines = new[] { dataLine };
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -248,30 +248,29 @@ namespace Shadowsocks.Controller
|
||||
Logging.Debug($"loading statistics from {path}");
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
Console.WriteLine($"statistics file does not exist, try to reload {RetryInterval/60/1000} minutes later");
|
||||
Console.WriteLine($"statistics file does not exist, try to reload {RetryInterval / 60 / 1000} minutes later");
|
||||
_timer.Change(RetryInterval, Interval);
|
||||
return;
|
||||
}
|
||||
RawStatistics = (from l in File.ReadAllLines(path)
|
||||
.Skip(1)
|
||||
let strings = l.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
|
||||
let rawData = new RawStatisticsData
|
||||
{
|
||||
Timestamp = ParseExactOrUnknown(strings[0]),
|
||||
ServerName = strings[1],
|
||||
ICMPStatus = strings[2],
|
||||
RoundtripTime = int.Parse(strings[3]),
|
||||
Geolocation = 5 > strings.Length ?
|
||||
null
|
||||
: strings[4],
|
||||
ISP = 6 > strings.Length ? null : strings[5]
|
||||
}
|
||||
group rawData by rawData.ServerName into server
|
||||
select new
|
||||
{
|
||||
ServerName = server.Key,
|
||||
data = server.ToList()
|
||||
}).ToDictionary(server => server.ServerName, server=> server.data);
|
||||
RawStatistics = (from l in File.ReadAllLines(path).Skip(1)
|
||||
let strings = l.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
|
||||
let rawData = new RawStatisticsData
|
||||
{
|
||||
Timestamp = ParseExactOrUnknown(strings[0]),
|
||||
ServerName = strings[1],
|
||||
ICMPStatus = strings[2],
|
||||
RoundtripTime = int.Parse(strings[3]),
|
||||
Geolocation = 5 > strings.Length ?
|
||||
null
|
||||
: strings[4],
|
||||
ISP = 6 > strings.Length ? null : strings[5]
|
||||
}
|
||||
group rawData by rawData.ServerName into server
|
||||
select new
|
||||
{
|
||||
ServerName = server.Key,
|
||||
data = server.ToList()
|
||||
}).ToDictionary(server => server.ServerName, server => server.data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -300,7 +299,7 @@ namespace Shadowsocks.Controller
|
||||
public string ICMPStatus;
|
||||
public int RoundtripTime;
|
||||
public string Geolocation;
|
||||
public string ISP ;
|
||||
public string ISP;
|
||||
}
|
||||
|
||||
public class StatisticsData
|
||||
@@ -310,6 +309,5 @@ namespace Shadowsocks.Controller
|
||||
public int MinResponse;
|
||||
public int MaxResponse;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using Shadowsocks.Properties;
|
||||
using SimpleJson;
|
||||
using Shadowsocks.Util;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
@@ -38,13 +38,13 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Utils.GetTempPath() + "\\gfwlist.txt", e.Result, Encoding.UTF8);
|
||||
File.WriteAllText(Utils.GetTempPath("gfwlist.txt"), e.Result, Encoding.UTF8);
|
||||
List<string> lines = ParseResult(e.Result);
|
||||
if (File.Exists(USER_RULE_FILE))
|
||||
{
|
||||
string local = File.ReadAllText(USER_RULE_FILE, Encoding.UTF8);
|
||||
string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach(string rule in rules)
|
||||
foreach (string rule in rules)
|
||||
{
|
||||
if (rule.StartsWith("!") || rule.StartsWith("["))
|
||||
continue;
|
||||
|
||||
@@ -146,8 +146,8 @@ Content-Type: application/x-ns-proxy-autoconfig
|
||||
Content-Length: {0}
|
||||
Connection: Close
|
||||
|
||||
", System.Text.Encoding.UTF8.GetBytes(pac).Length) + pac;
|
||||
byte[] response = System.Text.Encoding.UTF8.GetBytes(text);
|
||||
", Encoding.UTF8.GetBytes(pac).Length) + pac;
|
||||
byte[] response = Encoding.UTF8.GetBytes(text);
|
||||
socket.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), socket);
|
||||
Util.Utils.ReleaseMemory(true);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Properties;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
@@ -16,16 +16,14 @@ namespace Shadowsocks.Controller
|
||||
class PolipoRunner
|
||||
{
|
||||
private Process _process;
|
||||
private static string temppath;
|
||||
private int _runningPort;
|
||||
|
||||
static PolipoRunner()
|
||||
{
|
||||
temppath = Utils.GetTempPath();
|
||||
try
|
||||
{
|
||||
FileManager.UncompressFile(temppath + "/ss_privoxy.exe", Resources.privoxy_exe);
|
||||
FileManager.UncompressFile(temppath + "/mgwz.dll", Resources.mgwz_dll);
|
||||
FileManager.UncompressFile(Utils.GetTempPath("ss_privoxy.exe"), Resources.privoxy_exe);
|
||||
FileManager.UncompressFile(Utils.GetTempPath("mgwz.dll"), Resources.mgwz_dll);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
@@ -64,20 +62,16 @@ namespace Shadowsocks.Controller
|
||||
polipoConfig = polipoConfig.Replace("__SOCKS_PORT__", configuration.localPort.ToString());
|
||||
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_PORT__", _runningPort.ToString());
|
||||
polipoConfig = polipoConfig.Replace("__POLIPO_BIND_IP__", configuration.shareOverLan ? "0.0.0.0" : "127.0.0.1");
|
||||
FileManager.ByteArrayToFile(temppath + "/privoxy.conf", System.Text.Encoding.UTF8.GetBytes(polipoConfig));
|
||||
FileManager.ByteArrayToFile(Utils.GetTempPath("privoxy.conf"), Encoding.UTF8.GetBytes(polipoConfig));
|
||||
|
||||
if (!(temppath.EndsWith("\\") || temppath.EndsWith("/"))) {
|
||||
temppath = temppath + "\\";
|
||||
}
|
||||
_process = new Process();
|
||||
// Configure the process using the StartInfo properties.
|
||||
_process.StartInfo.FileName = temppath + "ss_privoxy.exe";
|
||||
_process.StartInfo.Arguments = " \"" + temppath + "privoxy.conf\"";
|
||||
_process.StartInfo.FileName = "ss_privoxy.exe";
|
||||
_process.StartInfo.Arguments = "privoxy.conf";
|
||||
_process.StartInfo.WorkingDirectory = Utils.GetTempPath();
|
||||
_process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
_process.StartInfo.UseShellExecute = true;
|
||||
_process.StartInfo.CreateNoWindow = true;
|
||||
//_process.StartInfo.RedirectStandardOutput = true;
|
||||
//_process.StartInfo.RedirectStandardError = true;
|
||||
_process.Start();
|
||||
}
|
||||
RefreshTrayArea();
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
|
||||
using SimpleJson;
|
||||
|
||||
using Shadowsocks.Model;
|
||||
@@ -129,8 +126,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
string temppath = Utils.GetTempPath();
|
||||
LatestVersionLocalName = Path.Combine(temppath, LatestVersionName);
|
||||
LatestVersionLocalName = Utils.GetTempPath(LatestVersionName);
|
||||
WebClient http = CreateWebClient();
|
||||
http.DownloadFileCompleted += Http_DownloadFileCompleted;
|
||||
http.DownloadFileAsync(new Uri(LatestVersionURL), LatestVersionLocalName);
|
||||
@@ -145,7 +141,7 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
if(e.Error != null)
|
||||
if (e.Error != null)
|
||||
{
|
||||
Logging.LogUsefulException(e.Error);
|
||||
return;
|
||||
@@ -241,6 +237,5 @@ namespace Shadowsocks.Controller
|
||||
return Asset.CompareVersion(x.version, y.version);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,12 +443,12 @@ namespace Shadowsocks.Controller
|
||||
private void pacServer_UserRuleFileChanged(object sender, EventArgs e)
|
||||
{
|
||||
// TODO: this is a dirty hack. (from code GListUpdater.http_DownloadStringCompleted())
|
||||
if (!File.Exists(Utils.GetTempPath() + "\\gfwlist.txt"))
|
||||
if (!File.Exists(Utils.GetTempPath("gfwlist.txt")))
|
||||
{
|
||||
UpdatePACFromGFWList();
|
||||
return;
|
||||
}
|
||||
List<string> lines = GFWListUpdater.ParseResult(File.ReadAllText(Utils.GetTempPath() + "\\gfwlist.txt"));
|
||||
List<string> lines = GFWListUpdater.ParseResult(File.ReadAllText(Utils.GetTempPath("gfwlist.txt")));
|
||||
if (File.Exists(PACServer.USER_RULE_FILE))
|
||||
{
|
||||
string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Encryption
|
||||
{
|
||||
@@ -15,8 +14,7 @@ namespace Shadowsocks.Encryption
|
||||
|
||||
static MbedTLS()
|
||||
{
|
||||
string tempPath = Utils.GetTempPath();
|
||||
string dllPath = tempPath + "/libsscrypto.dll";
|
||||
string dllPath = Utils.GetTempPath("libsscrypto.dll");
|
||||
try
|
||||
{
|
||||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
|
||||
@@ -59,10 +57,9 @@ namespace Shadowsocks.Encryption
|
||||
public extern static void md5_starts(IntPtr ctx);
|
||||
|
||||
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
public extern static void md5_update(IntPtr ctx, byte[] input, uint ilen );
|
||||
public extern static void md5_update(IntPtr ctx, byte[] input, uint ilen);
|
||||
|
||||
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
public extern static void md5_finish(IntPtr ctx, byte[] output);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Encryption
|
||||
{
|
||||
@@ -19,8 +18,7 @@ namespace Shadowsocks.Encryption
|
||||
|
||||
static PolarSSL()
|
||||
{
|
||||
string tempPath = Utils.GetTempPath();
|
||||
string dllPath = tempPath + "/libsscrypto.dll";
|
||||
string dllPath = Utils.GetTempPath("libsscrypto.dll");
|
||||
try
|
||||
{
|
||||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
|
||||
@@ -63,6 +61,5 @@ namespace Shadowsocks.Encryption
|
||||
|
||||
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
||||
public extern static int arc4_crypt(IntPtr ctx, int length, byte[] input, byte[] output);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.Util;
|
||||
|
||||
namespace Shadowsocks.Encryption
|
||||
{
|
||||
@@ -15,8 +14,7 @@ namespace Shadowsocks.Encryption
|
||||
|
||||
static Sodium()
|
||||
{
|
||||
string tempPath = Utils.GetTempPath();
|
||||
string dllPath = tempPath + "/libsscrypto.dll";
|
||||
string dllPath = Utils.GetTempPath("libsscrypto.dll");
|
||||
try
|
||||
{
|
||||
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
|
||||
@@ -47,7 +45,6 @@ namespace Shadowsocks.Encryption
|
||||
public extern static void ss_sha1_hmac_ex(byte[] key, uint keylen,
|
||||
byte[] input, int ioff, uint ilen,
|
||||
byte[] output);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Properties;
|
||||
using Shadowsocks.View;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Util;
|
||||
using Shadowsocks.View;
|
||||
|
||||
namespace Shadowsocks
|
||||
{
|
||||
static class Program
|
||||
@@ -18,7 +18,7 @@ namespace Shadowsocks
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Util.Utils.ReleaseMemory(true);
|
||||
Utils.ReleaseMemory(true);
|
||||
using (Mutex mutex = new Mutex(false, "Global\\Shadowsocks_" + Application.StartupPath.GetHashCode()))
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
@@ -37,15 +37,19 @@ namespace Shadowsocks
|
||||
return;
|
||||
}
|
||||
Directory.SetCurrentDirectory(Application.StartupPath);
|
||||
|
||||
#if DEBUG
|
||||
Logging.OpenLogFile();
|
||||
|
||||
// truncate privoxy log file while debugging
|
||||
string privoxyLogFilename = Utils.GetTempPath("privoxy.log");
|
||||
if (File.Exists(privoxyLogFilename))
|
||||
using (new FileStream(privoxyLogFilename, FileMode.Truncate)) { }
|
||||
#else
|
||||
Logging.OpenLogFile();
|
||||
#endif
|
||||
ShadowsocksController controller = new ShadowsocksController();
|
||||
|
||||
MenuViewController viewController = new MenuViewController(controller);
|
||||
|
||||
controller.Start();
|
||||
|
||||
Application.Run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,23 +11,38 @@ namespace Shadowsocks.Util
|
||||
{
|
||||
public class Utils
|
||||
{
|
||||
private static string TempPath = null;
|
||||
|
||||
// return path to store temporary files
|
||||
public static string GetTempPath()
|
||||
{
|
||||
if (File.Exists(Application.StartupPath + "\\shadowsocks_portable_mode.txt"))
|
||||
if (TempPath == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Application.StartupPath + "\\temp");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
// don't use "/", it will fail when we call explorer /select xxx/temp\xxx.log
|
||||
return Application.StartupPath + "\\temp";
|
||||
if (File.Exists(Path.Combine(Application.StartupPath, "shadowsocks_portable_mode.txt")))
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(Application.StartupPath, "temp"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TempPath = Path.GetTempPath();
|
||||
Logging.LogUsefulException(e);
|
||||
}
|
||||
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 Path.GetTempPath();
|
||||
return TempPath;
|
||||
}
|
||||
|
||||
// return a full path with filename combined which pointed to the temporary directory
|
||||
public static string GetTempPath(string filename)
|
||||
{
|
||||
return Path.Combine(GetTempPath(), filename);
|
||||
}
|
||||
|
||||
public static void ReleaseMemory(bool removePages)
|
||||
|
||||
Reference in New Issue
Block a user