Compare commits
4 Commits
1dc3d93edf
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 14ac62828d | |||
|
|
a07655faed | ||
| f7b63cb8e1 | |||
|
|
bb6c229875 |
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31911.196
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Networking", "Networking\Networking.csproj", "{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Networking", "Networking\Networking.csproj", "{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApp1", "WpfApp1\WpfApp1.csproj", "{89252909-F8E2-4BDB-8EA9-4DA1A329545C}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -15,6 +17,10 @@ Global
|
|||||||
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{89252909-F8E2-4BDB-8EA9-4DA1A329545C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
104
Networking/IPScannerLib/HiResTimer.cs
Normal file
104
Networking/IPScannerLib/HiResTimer.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace IPScanner
|
||||||
|
{
|
||||||
|
public class HiResTimer
|
||||||
|
{
|
||||||
|
private bool isPerfCounterSupported = false;
|
||||||
|
private Int64 frequency = 0;
|
||||||
|
|
||||||
|
// Windows CE native library with QueryPerformanceCounter().
|
||||||
|
private const string lib = "Kernel32.dll";
|
||||||
|
[DllImport(lib)]
|
||||||
|
private static extern int QueryPerformanceCounter(ref Int64 count);
|
||||||
|
[DllImport(lib)]
|
||||||
|
private static extern int QueryPerformanceFrequency(ref Int64 frequency);
|
||||||
|
|
||||||
|
public HiResTimer()
|
||||||
|
{
|
||||||
|
// Query the high-resolution timer only if it is supported.
|
||||||
|
// A returned frequency of 1000 typically indicates that it is not
|
||||||
|
// supported and is emulated by the OS using the same value that is
|
||||||
|
// returned by Environment.TickCount.
|
||||||
|
// A return value of 0 indicates that the performance counter is
|
||||||
|
// not supported.
|
||||||
|
int returnVal = QueryPerformanceFrequency(ref frequency);
|
||||||
|
|
||||||
|
if (returnVal != 0 && frequency != 1000)
|
||||||
|
{
|
||||||
|
// The performance counter is supported.
|
||||||
|
isPerfCounterSupported = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The performance counter is not supported. Use
|
||||||
|
// Environment.TickCount instead.
|
||||||
|
frequency = 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Int64 Frequency
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return frequency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Int64 Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (isPerfCounterSupported)
|
||||||
|
{
|
||||||
|
// Get the value here if the counter is supported.
|
||||||
|
Int64 tickCount = 0;
|
||||||
|
QueryPerformanceCounter(ref tickCount);
|
||||||
|
return tickCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise, use Environment.TickCount.
|
||||||
|
return (Int64)Environment.TickCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Int64 start;
|
||||||
|
private bool isRunning = false;
|
||||||
|
private double elapsedMillisecondsAtTimeOfStop = 0;
|
||||||
|
public double ElapsedMilliseconds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (isRunning)
|
||||||
|
{
|
||||||
|
Int64 timeElapsedInTicks = Value - start;
|
||||||
|
return (timeElapsedInTicks * 1000) / Frequency;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return elapsedMillisecondsAtTimeOfStop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
start = Value;
|
||||||
|
isRunning = true;
|
||||||
|
}
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (!isRunning)
|
||||||
|
return;
|
||||||
|
elapsedMillisecondsAtTimeOfStop = ElapsedMilliseconds;
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
isRunning = false;
|
||||||
|
elapsedMillisecondsAtTimeOfStop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
185
Networking/IPScannerLib/HttpHelper.cs
Normal file
185
Networking/IPScannerLib/HttpHelper.cs
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Net.Configuration;
|
||||||
|
|
||||||
|
namespace IPScanner
|
||||||
|
{
|
||||||
|
public class HttpResponseData
|
||||||
|
{
|
||||||
|
public string data;
|
||||||
|
public SortedList<string, string> headers;
|
||||||
|
public string host;
|
||||||
|
public HttpResponseData(string data, SortedList<string, string> headers, string host)
|
||||||
|
{
|
||||||
|
this.data = data;
|
||||||
|
this.headers = headers;
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
public string GetHeaderValue(string key)
|
||||||
|
{
|
||||||
|
string val;
|
||||||
|
if (headers.TryGetValue(key.ToLower(), out val))
|
||||||
|
return val;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static class HttpHelper
|
||||||
|
{
|
||||||
|
static HttpHelper()
|
||||||
|
{
|
||||||
|
ToggleAllowUnsafeHeaderParsing(true);
|
||||||
|
}
|
||||||
|
public static HttpResponseData GetHttpResponseData(string url)
|
||||||
|
{
|
||||||
|
SortedList<string, string> headers = new SortedList<string, string>();
|
||||||
|
//return new HttpResponseData("", headers, url);
|
||||||
|
byte[] data = GetData(url, headers);
|
||||||
|
return new HttpResponseData(UTF8Encoding.UTF8.GetString(data), headers, url);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets data from a URL and returns it as a byte array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte[] GetData(string url, SortedList<string, string> headers = null, string user = "", string password = "", bool keepAlive = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (url.Contains(".80"))
|
||||||
|
{
|
||||||
|
Console.WriteLine(url);
|
||||||
|
}
|
||||||
|
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
|
||||||
|
webRequest.Proxy = null;
|
||||||
|
webRequest.KeepAlive = keepAlive;
|
||||||
|
webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(user) || !string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
string authInfo = user + ":" + password;
|
||||||
|
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
|
||||||
|
webRequest.Headers["Authorization"] = "Basic " + authInfo;
|
||||||
|
}
|
||||||
|
webRequest.Method = "GET";
|
||||||
|
webRequest.Timeout = 5000;
|
||||||
|
webRequest.AllowAutoRedirect = true;
|
||||||
|
return GetResponse(webRequest, headers);
|
||||||
|
}
|
||||||
|
catch (ThreadAbortException ex) { throw ex; }
|
||||||
|
catch (WebException ex)
|
||||||
|
{
|
||||||
|
if (ex.Message.StartsWith("The server committed a protocol violation"))
|
||||||
|
return UTF8Encoding.UTF8.GetBytes(ex.Message);
|
||||||
|
if (ex.Message == "The remote server returned an error: (404) Not Found." || ex.Message == "The remote server returned an error: (401) Unauthorized.")
|
||||||
|
{
|
||||||
|
|
||||||
|
//if(ex.Response.ResponseUri.AbsolutePath == "/nocookies.html")
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return GetResponseData(ex.Response, headers);
|
||||||
|
}
|
||||||
|
catch (ThreadAbortException e) { throw e; }
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (url.Contains(".80"))
|
||||||
|
{
|
||||||
|
Console.WriteLine(e.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//else if (ex.Message == "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel." && url.StartsWith("http:"))
|
||||||
|
//{
|
||||||
|
// url = "https" + url.Substring(4);
|
||||||
|
// return GetData(url, headers, user, password, keepAlive);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (url.Contains(".80"))
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
private static byte[] GetResponse(HttpWebRequest webRequest, SortedList<string, string> headers = null)
|
||||||
|
{
|
||||||
|
return GetResponseData((HttpWebResponse)webRequest.GetResponse(), headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetResponseData(WebResponse webResponseObj, SortedList<string, string> headers = null)
|
||||||
|
{
|
||||||
|
byte[] data;
|
||||||
|
using (HttpWebResponse webResponse = (HttpWebResponse)webResponseObj)
|
||||||
|
{
|
||||||
|
using (MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (Stream responseStream = webResponse.GetResponseStream())
|
||||||
|
{
|
||||||
|
// Dump the response stream into the MemoryStream ms
|
||||||
|
int bytesRead = 1;
|
||||||
|
while (bytesRead > 0)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[8000];
|
||||||
|
bytesRead = responseStream.Read(buffer, 0, buffer.Length);
|
||||||
|
if (bytesRead > 0)
|
||||||
|
ms.Write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
data = new byte[ms.Length];
|
||||||
|
|
||||||
|
// Dump the data into the byte array
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
ms.Read(data, 0, data.Length);
|
||||||
|
responseStream.Close();
|
||||||
|
|
||||||
|
if (headers != null)
|
||||||
|
foreach (string key in webResponse.Headers.AllKeys)
|
||||||
|
headers[key.ToLower()] = webResponse.Headers[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webResponse.Close();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable/disable useUnsafeHeaderParsing.
|
||||||
|
/// See http://o2platform.wordpress.com/2010/10/20/dealing-with-the-server-committed-a-protocol-violation-sectionresponsestatusline/
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool ToggleAllowUnsafeHeaderParsing(bool enable)
|
||||||
|
{
|
||||||
|
//Get the assembly that contains the internal class
|
||||||
|
Assembly assembly = Assembly.GetAssembly(typeof(SettingsSection));
|
||||||
|
if (assembly != null)
|
||||||
|
{
|
||||||
|
//Use the assembly in order to get the internal type for the internal class
|
||||||
|
Type settingsSectionType = assembly.GetType("System.Net.Configuration.SettingsSectionInternal");
|
||||||
|
if (settingsSectionType != null)
|
||||||
|
{
|
||||||
|
//Use the internal static property to get an instance of the internal settings class.
|
||||||
|
//If the static instance isn't created already invoking the property will create it for us.
|
||||||
|
object anInstance = settingsSectionType.InvokeMember("Section", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { });
|
||||||
|
if (anInstance != null)
|
||||||
|
{
|
||||||
|
//Locate the private bool field that tells the framework if unsafe header parsing is allowed
|
||||||
|
FieldInfo aUseUnsafeHeaderParsing = settingsSectionType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
if (aUseUnsafeHeaderParsing != null)
|
||||||
|
{
|
||||||
|
aUseUnsafeHeaderParsing.SetValue(anInstance, enable);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
Networking/IPScannerLib/IPRanges.cs
Normal file
53
Networking/IPScannerLib/IPRanges.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace IPScanner
|
||||||
|
{
|
||||||
|
public static class IPRanges
|
||||||
|
{
|
||||||
|
public static List<Tuple<IPAddress, IPAddress>> GetOperationalIPRanges()
|
||||||
|
{
|
||||||
|
List<Tuple<IPAddress, IPAddress>> ranges = new List<Tuple<IPAddress, IPAddress>>();
|
||||||
|
|
||||||
|
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
|
||||||
|
{
|
||||||
|
if (netInterface.OperationalStatus != OperationalStatus.Up)
|
||||||
|
continue;
|
||||||
|
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
|
||||||
|
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
|
||||||
|
{
|
||||||
|
if (addr.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
|
ranges.Add(new Tuple<IPAddress, IPAddress>(GetLowestInRange(addr.Address, addr.IPv4Mask), GetHighestInRange(addr.Address, addr.IPv4Mask)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
private static IPAddress GetLowestInRange(IPAddress address, IPAddress mask)
|
||||||
|
{
|
||||||
|
byte[] addressBytes = address.GetAddressBytes();
|
||||||
|
byte[] maskBytes = mask.GetAddressBytes();
|
||||||
|
if (addressBytes.Length != 4 || maskBytes.Length != 4)
|
||||||
|
return IPAddress.None;
|
||||||
|
byte[] lowest = new byte[4];
|
||||||
|
for (var i = 0; i < 4; i++)
|
||||||
|
lowest[i] = (byte)(addressBytes[i] & maskBytes[i]);
|
||||||
|
return new IPAddress(lowest);
|
||||||
|
}
|
||||||
|
private static IPAddress GetHighestInRange(IPAddress address, IPAddress mask)
|
||||||
|
{
|
||||||
|
byte[] addressBytes = address.GetAddressBytes();
|
||||||
|
byte[] maskBytes = mask.GetAddressBytes();
|
||||||
|
if (addressBytes.Length != 4 || maskBytes.Length != 4)
|
||||||
|
return IPAddress.None;
|
||||||
|
byte[] highest = new byte[4];
|
||||||
|
for (var i = 0; i < 4; i++)
|
||||||
|
highest[i] = (byte)((addressBytes[i] & maskBytes[i]) | ~maskBytes[i]);
|
||||||
|
return new IPAddress(highest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Networking/IPScannerLib/IPScanResult.cs
Normal file
29
Networking/IPScannerLib/IPScanResult.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace IPScanner
|
||||||
|
{
|
||||||
|
public class IPScanResult
|
||||||
|
{
|
||||||
|
public IPAddress ip;
|
||||||
|
public int ping = -1;
|
||||||
|
public string host;
|
||||||
|
public ScanStatus status = ScanStatus.Initializing;
|
||||||
|
public string identification = "...";
|
||||||
|
public HttpResponseData response;
|
||||||
|
|
||||||
|
public IPScanResult(IPAddress ip)
|
||||||
|
{
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
//public IPScanResult(IPAddress ip, int ping, string host)
|
||||||
|
//{
|
||||||
|
// this.ip = ip;
|
||||||
|
// this.ping = ping;
|
||||||
|
// this.host = host;
|
||||||
|
// this.status = ScanStatus.Complete;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
238
Networking/IPScannerLib/NetworkScanner.cs
Normal file
238
Networking/IPScannerLib/NetworkScanner.cs
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using Amib.Threading;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace IPScanner
|
||||||
|
{
|
||||||
|
public class NetworkScanner
|
||||||
|
{
|
||||||
|
private static Regex rxHtmlTitle = new Regex("<title>([^<]+?)</title>", RegexOptions.Compiled);
|
||||||
|
SmartThreadPool Pool = new SmartThreadPool(1000, 256, 0);
|
||||||
|
public NetworkScanner()
|
||||||
|
{
|
||||||
|
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||||
|
System.Net.ServicePointManager.MaxServicePoints = int.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IPScanResult> BeginScan(IPAddress ipFrom, IPAddress ipTo)
|
||||||
|
{
|
||||||
|
Amib.Threading.Action<IPAddress, List<IPScanResult>, int> ipScanAction = new Amib.Threading.Action<IPAddress, List<IPScanResult>, int>(ScanIPAsync);
|
||||||
|
// Count the IP addresses included in this range
|
||||||
|
byte[] addyEnd = ipTo.GetAddressBytes();
|
||||||
|
byte[] addyNext = ipFrom.GetAddressBytes();
|
||||||
|
|
||||||
|
List<IPScanResult> Results = new List<IPScanResult>();
|
||||||
|
while (CompareIPs(addyNext, addyEnd) < 1)
|
||||||
|
{
|
||||||
|
Results.Add(new IPScanResult(new IPAddress(addyNext)));
|
||||||
|
IncrementIP(addyNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Results.Count; i++)
|
||||||
|
Pool.QueueWorkItem(ipScanAction, Results[i].ip, Results, i);
|
||||||
|
return Results;
|
||||||
|
}
|
||||||
|
private void ScanIPAsync(IPAddress ip, List<IPScanResult> results, int listIndex)
|
||||||
|
{
|
||||||
|
bool foundHost = false;
|
||||||
|
results[listIndex].status = ScanStatus.Initializing;
|
||||||
|
|
||||||
|
// Attempt Ordinary Ping
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (Ping p = new Ping())
|
||||||
|
{
|
||||||
|
PingReply pingReply = p.Send(ip, 5000);
|
||||||
|
if (pingReply.Status == IPStatus.Success)
|
||||||
|
{
|
||||||
|
foundHost = true;
|
||||||
|
results[listIndex].status = ScanStatus.Partial;
|
||||||
|
results[listIndex].ping = (int)pingReply.RoundtripTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SocketException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt DNS Lookup
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Stopwatch timer = new Stopwatch();
|
||||||
|
timer.Start();
|
||||||
|
IPHostEntry ipe = Dns.GetHostEntry(ip);
|
||||||
|
timer.Stop();
|
||||||
|
int dnsLookupTime = (int)timer.ElapsedMilliseconds;
|
||||||
|
|
||||||
|
foundHost = true;
|
||||||
|
//if (results[listIndex].ping < 0 || dnsLookupTime < results[listIndex].ping)
|
||||||
|
// results[listIndex].ping = dnsLookupTime;
|
||||||
|
results[listIndex].host = ipe.HostName.ToString();
|
||||||
|
results[listIndex].status = ScanStatus.Complete;
|
||||||
|
}
|
||||||
|
//catch (SocketException ex)
|
||||||
|
//{
|
||||||
|
// //if (ex.SocketErrorCode == SocketError.HostNotFound)
|
||||||
|
// // return;
|
||||||
|
// Console.WriteLine(ex.Message);
|
||||||
|
//}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (foundHost)
|
||||||
|
{
|
||||||
|
// Try to identify
|
||||||
|
HttpResponseData response;
|
||||||
|
results[listIndex].identification = IdentifyHost(ip, out response);
|
||||||
|
results[listIndex].status = ScanStatus.Complete;
|
||||||
|
results[listIndex].response = response;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
results[listIndex].status = ScanStatus.NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string IdentifyHost(IPAddress ip, out HttpResponseData response)
|
||||||
|
{
|
||||||
|
response = null;
|
||||||
|
Stopwatch sw = new Stopwatch();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sw.Start();
|
||||||
|
response = HttpHelper.GetHttpResponseData("http://" + ip.ToString() + "/");
|
||||||
|
if (response.GetHeaderValue("server").StartsWith("lighttpd") && response.GetHeaderValue("set-cookie").Contains("AIROS_") && response.data.Contains("<title>Error 404"))
|
||||||
|
return "Ubiquiti";
|
||||||
|
else if (response.GetHeaderValue("server").StartsWith("Boa") && response.data.Contains("<OBJECT ID=\"TSConfigIPCCtrl\""))
|
||||||
|
return "Generic IP Cam"; // CCDCam EC-IP5911
|
||||||
|
else if (response.data.Contains("flow_slct = get_slctid('flowtype');"))
|
||||||
|
return "IPS Cam";
|
||||||
|
else if (response.GetHeaderValue("server") == "GoAhead-Webs" && response.data.Contains("document.location = '/live.asp?"))
|
||||||
|
return "Edimax Cam";
|
||||||
|
else if (response.GetHeaderValue("server").StartsWith("App-webs/") && response.data.Contains("window.location.href = \"doc/page/login.asp"))
|
||||||
|
return "Hikvision";
|
||||||
|
else if (response.data.Contains("src=\"jsCore/LAB.js\"") || response.data.Contains("var lt = \"?WebVersion=") || response.data.Contains("src=\"jsCore/rpcCore.js"))
|
||||||
|
return "Dahua";
|
||||||
|
else if (response.GetHeaderValue("www-authenticate").Contains("realm=\"tomato\""))
|
||||||
|
return "Tomato";
|
||||||
|
else if (response.GetHeaderValue("server") == "Web Server" && response.data.Contains("<TITLE>NETGEAR FS728TP</TITLE>"))
|
||||||
|
return "Netgear FS728TP";
|
||||||
|
else if (response.GetHeaderValue("set-cookie").Contains("DLILPC=") && response.data.Contains("<title>Power Controller"))
|
||||||
|
return "Web Power Switch";
|
||||||
|
else if (response.data == "The server committed a protocol violation. Section=ResponseStatusLine")
|
||||||
|
return "? WeatherDirect ?";
|
||||||
|
else if (response.data == "The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF")
|
||||||
|
return "? Web Power Switch ?";
|
||||||
|
else if (response.data.Contains("NetDAQ ND-100"))
|
||||||
|
return "NetDAQ ND-100";
|
||||||
|
else if (response.GetHeaderValue("server") == "nginx" && response.data.Contains("<title>airVision:"))
|
||||||
|
return "AirVision NVR";
|
||||||
|
else if (response.GetHeaderValue("server") == "nginx" && response.data.Contains("<title>airVision:"))
|
||||||
|
return "AirVision NVR";
|
||||||
|
else if (response.GetHeaderValue("server").StartsWith("BlueIris-"))
|
||||||
|
return "Blue Iris";
|
||||||
|
//else if (response.data.Contains("<title>iTach"))
|
||||||
|
// return "iTach";
|
||||||
|
else if (response.data.Contains("href=\"/cmh\""))
|
||||||
|
return "Vera";
|
||||||
|
else if (response.data.Contains("WDMyCloud"))
|
||||||
|
return "WDMyCloud";
|
||||||
|
//else if (response.data.Contains("<title>DD-WRT"))
|
||||||
|
// return "DD-WRT";
|
||||||
|
else if (response.data.Contains("= \"Peplink\""))
|
||||||
|
return "Peplink";
|
||||||
|
else if (response.data.Contains("GSViewerX.ocx"))
|
||||||
|
return "GrandStream";
|
||||||
|
else if (response.data.Contains("content=\"Canon Inc.\""))
|
||||||
|
return "Canon printer";
|
||||||
|
else if (response.GetHeaderValue("server") == "tsbox" && response.GetHeaderValue("www-authenticate") == "Basic realm=\"pbox\"")
|
||||||
|
return "HDMI Encoder";
|
||||||
|
else if (response.data.Contains("Rules of login password.\\n"))
|
||||||
|
return "ACTi";
|
||||||
|
else if (response.data.Contains("/static/freenas_favicon.ico"))
|
||||||
|
return "FreeNAS";
|
||||||
|
else if (response.data.Contains("CONTENT=\"0;url=cgi-bin/kvm.cgi\""))
|
||||||
|
return "Avocent KVM";
|
||||||
|
else if (response.GetHeaderValue("www-authenticate") == "Basic realm=\"TomatoUSB\"")
|
||||||
|
return "TomatoUSB Router";
|
||||||
|
else if (response.GetHeaderValue("auther") == "Steven Wu" && response.GetHeaderValue("server") == "Camera Web Server/1.0" && response.data.Contains("location.href=\"top.htm?Currenttime=\"+timeValue;"))
|
||||||
|
return "TrendNET IP cam";
|
||||||
|
else if (response.data.Contains(@"<meta http-equiv=""refresh"" content=""0;URL='/ui'""/>"))
|
||||||
|
return "ESXi";
|
||||||
|
else if (response.GetHeaderValue("server") == "Microsoft-HTTPAPI/2.0")
|
||||||
|
return "IIS";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Match m = rxHtmlTitle.Match(response.data);
|
||||||
|
if (m.Success)
|
||||||
|
return m.Groups[1].Value;
|
||||||
|
string server = response.GetHeaderValue("server");
|
||||||
|
if (!string.IsNullOrEmpty(server))
|
||||||
|
return server;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
//Console.WriteLine("Spent " + sw.ElapsedMilliseconds + " on " + response.data.Length);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Abort()
|
||||||
|
{
|
||||||
|
Pool.Cancel(true);
|
||||||
|
}
|
||||||
|
bool ArraysMatch(Array a1, Array a2)
|
||||||
|
{
|
||||||
|
if (a1.Length != a2.Length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < a1.Length; i++)
|
||||||
|
if (a1.GetValue(i) != a1.GetValue(i))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int CompareIPs(byte[] ip1, byte[] ip2)
|
||||||
|
{
|
||||||
|
if (ip1 == null || ip1.Length != 4)
|
||||||
|
return -1;
|
||||||
|
if (ip2 == null || ip2.Length != 4)
|
||||||
|
return 1;
|
||||||
|
int comp = ip1[0].CompareTo(ip2[0]);
|
||||||
|
if (comp == 0)
|
||||||
|
comp = ip1[1].CompareTo(ip2[1]);
|
||||||
|
if (comp == 0)
|
||||||
|
comp = ip1[2].CompareTo(ip2[2]);
|
||||||
|
if (comp == 0)
|
||||||
|
comp = ip1[3].CompareTo(ip2[3]);
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
void IncrementIP(byte[] ip, int idx = 3)
|
||||||
|
{
|
||||||
|
if (ip == null || ip.Length != 4 || idx < 0)
|
||||||
|
return;
|
||||||
|
if (ip[idx] == 254)
|
||||||
|
{
|
||||||
|
ip[idx] = 1;
|
||||||
|
IncrementIP(ip, idx - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ip[idx] = (byte)(ip[idx] + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Networking/IPScannerLib/ScanStatus.cs
Normal file
15
Networking/IPScannerLib/ScanStatus.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace IPScanner
|
||||||
|
{
|
||||||
|
public enum ScanStatus
|
||||||
|
{
|
||||||
|
Initializing,
|
||||||
|
Scanning,
|
||||||
|
NotFound,
|
||||||
|
Complete,
|
||||||
|
Partial
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,10 +37,18 @@
|
|||||||
<Reference Include="PresentationCore" />
|
<Reference Include="PresentationCore" />
|
||||||
<Reference Include="PresentationFramework" />
|
<Reference Include="PresentationFramework" />
|
||||||
<Reference Include="PTConverter.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="PTConverter.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\PTConverter.Plugin.1.0.2\lib\net472\PTConverter.Plugin.dll</HintPath>
|
<HintPath>..\packages\PTConverter.Plugin.1.0.3\lib\net472\PTConverter.Plugin.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Configuration" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.IO.Compression" />
|
||||||
|
<Reference Include="System.Runtime.Serialization" />
|
||||||
|
<Reference Include="System.ServiceModel" />
|
||||||
|
<Reference Include="System.Transactions" />
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xaml" />
|
<Reference Include="System.Xaml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
@@ -48,17 +56,87 @@
|
|||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="UIAutomationProvider" />
|
||||||
<Reference Include="WindowsBase" />
|
<Reference Include="WindowsBase" />
|
||||||
|
<Reference Include="WindowsFormsIntegration" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="IPTool.cs" />
|
<Compile Include="IPScannerLib\HiResTimer.cs" />
|
||||||
<Compile Include="Networking.IPv4.xaml.cs">
|
<Compile Include="IPScannerLib\HttpHelper.cs" />
|
||||||
<DependentUpon>Networking.IPv4.xaml</DependentUpon>
|
<Compile Include="IPScannerLib\IPRanges.cs" />
|
||||||
|
<Compile Include="IPScannerLib\IPScanResult.cs" />
|
||||||
|
<Compile Include="IPScannerLib\IPTool.cs" />
|
||||||
|
<Compile Include="IPScannerLib\NetworkScanner.cs" />
|
||||||
|
<Compile Include="IPScannerLib\ScanStatus.cs" />
|
||||||
|
<Compile Include="Pages\PortScanner.xaml.cs">
|
||||||
|
<DependentUpon>PortScanner.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Pages\WF_PortScanner.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Pages\WF_PortScanner.Designer.cs">
|
||||||
|
<DependentUpon>WF_PortScanner.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="PortScanner\InputChecker.cs" />
|
||||||
|
<Compile Include="PortScanner\IScannerManagerSingleton.cs" />
|
||||||
|
<Compile Include="Pages\IPScanner.xaml.cs">
|
||||||
|
<DependentUpon>IPScanner.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Pages\IPv4.xaml.cs">
|
||||||
|
<DependentUpon>IPv4.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Pages\WF_IPScanner.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Pages\WF_IPScanner.Designer.cs">
|
||||||
|
<DependentUpon>WF_IPScanner.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="PluginInfo.cs" />
|
||||||
|
<Compile Include="PortScanner\PortScannerBase.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="PortScanner\ScannerManagerSingleton.cs" />
|
||||||
|
<Compile Include="PortScanner\Settings.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\CallerThreadContext.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\CanceledWorkItemsGroup.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\EventWaitHandle.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\EventWaitHandleFactory.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\Exceptions.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\Interfaces.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\InternalInterfaces.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\PriorityQueue.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\SLExt.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\SmartThreadPool.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\SmartThreadPool.ThreadEntry.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\Stopwatch.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\STPEventWaitHandle.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\STPPerformanceCounter.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\STPStartInfo.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\SynchronizedDictionary.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WIGStartInfo.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItem.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItem.WorkItemResult.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItemFactory.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItemInfo.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItemResultTWrapper.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItemsGroup.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItemsGroupBase.cs" />
|
||||||
|
<Compile Include="SmartThreadPool\WorkItemsQueue.cs" />
|
||||||
|
<Compile Include="PortScanner\TCPPortScanner.cs" />
|
||||||
|
<Compile Include="PortScanner\TimeoutListItem.cs" />
|
||||||
|
<Compile Include="PortScanner\UDPPortScanner.cs" />
|
||||||
|
<Compile Include="Util\HelperMethods.cs" />
|
||||||
|
<Compile Include="Util\TimeSpanUtil.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Include="Networking.IPv4.xaml">
|
<Page Include="Pages\IPScanner.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Pages\IPv4.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Pages\PortScanner.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -69,5 +147,13 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Pages\WF_IPScanner.resx">
|
||||||
|
<DependentUpon>WF_IPScanner.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Pages\WF_PortScanner.resx">
|
||||||
|
<DependentUpon>WF_PortScanner.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
12
Networking/Pages/IPScanner.xaml
Normal file
12
Networking/Pages/IPScanner.xaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<UserControl x:Class="Networking.Pages.IPScanner"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Networking.Pages"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800" Background="White">
|
||||||
|
<WindowsFormsHost>
|
||||||
|
<local:WF_IPScanner/>
|
||||||
|
</WindowsFormsHost>
|
||||||
|
</UserControl>
|
||||||
50
Networking/Pages/IPScanner.xaml.cs
Normal file
50
Networking/Pages/IPScanner.xaml.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using IPScanner;
|
||||||
|
using PTConverter.Plugin;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Timers;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Networking.Pages
|
||||||
|
{
|
||||||
|
public class Device
|
||||||
|
{
|
||||||
|
public string IP { get; set; }
|
||||||
|
public string Ping { get; set; }
|
||||||
|
public string Host { get; set; }
|
||||||
|
public string Identification { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für Networking.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class IPScanner : UserControl, IPage
|
||||||
|
{
|
||||||
|
public IPScanner()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetCategory() => "Networking";
|
||||||
|
|
||||||
|
public UserControl GetPage() => new IPScanner();
|
||||||
|
|
||||||
|
public string GetUnderCategory() => "IPScanner";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
<UserControl x:Class="Networking.Networking_IPv4"
|
<UserControl x:Class="Networking.Pages.IPv4"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Networking"
|
xmlns:local="clr-namespace:Networking.Pages"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800" Background="White">
|
d:DesignHeight="450" d:DesignWidth="800" Background="White">
|
||||||
<Grid>
|
<Grid>
|
||||||
<ComboBox x:Name="tbNETClass" HorizontalAlignment="Left" Margin="328,61,0,0" VerticalAlignment="Top" Width="266" SelectionChanged="netClassComboBox_SelectedIndexChanged"/>
|
<ComboBox x:Name="tbNETClass" HorizontalAlignment="Left" Margin="328,61,0,0" VerticalAlignment="Top" Width="266" SelectionChanged="netClassComboBox_SelectedIndexChanged"/>
|
||||||
<TextBox x:Name="tbIPAddressP1" Text="255" HorizontalAlignment="Left" Height="23" Margin="39,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" />
|
<TextBox x:Name="tbIPAddressP1" Text="255" HorizontalAlignment="Left" Height="23" Margin="39,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" TabIndex="0" />
|
||||||
<ComboBox x:Name="prefixComboBox" HorizontalAlignment="Left" Margin="134,177,0,0" VerticalAlignment="Top" Width="99" Height="28" SelectionChanged="prefixComboBox_SelectedIndexChanged"/>
|
<ComboBox x:Name="prefixComboBox" HorizontalAlignment="Left" Margin="134,177,0,0" VerticalAlignment="Top" Width="99" Height="28" SelectionChanged="prefixComboBox_SelectedIndexChanged"/>
|
||||||
<ComboBox x:Name="netMaskComboBox" HorizontalAlignment="Left" Margin="328,177,0,0" VerticalAlignment="Top" Width="266" Height="28" SelectionChanged="netMaskComboBox_SelectedIndexChanged"/>
|
<ComboBox x:Name="netMaskComboBox" HorizontalAlignment="Left" Margin="328,177,0,0" VerticalAlignment="Top" Width="266" Height="28" SelectionChanged="netMaskComboBox_SelectedIndexChanged"/>
|
||||||
<CheckBox x:Name="firstBitCheckBox" Content="Allow 1st subnet-BIT" HorizontalAlignment="Left" Margin="654,177,0,0" VerticalAlignment="Top"/>
|
<CheckBox x:Name="firstBitCheckBox" Content="Allow 1st subnet-BIT" HorizontalAlignment="Left" Margin="654,177,0,0" VerticalAlignment="Top"/>
|
||||||
<TextBox x:Name="maxCountHosts" HorizontalAlignment="Left" Height="24" Margin="258,236,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336"/>
|
<TextBox x:Name="maxCountHosts" HorizontalAlignment="Left" Height="24" Margin="258,236,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336" TabIndex="4"/>
|
||||||
<TextBox x:Name="calcNetwork" HorizontalAlignment="Left" Height="24" Margin="258,265,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336"/>
|
<TextBox x:Name="calcNetwork" HorizontalAlignment="Left" Height="24" Margin="258,265,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336" TabIndex="5"/>
|
||||||
<TextBox x:Name="calcBroadcast" HorizontalAlignment="Left" Height="24" Margin="258,294,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336"/>
|
<TextBox x:Name="calcBroadcast" HorizontalAlignment="Left" Height="24" Margin="258,294,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336" TabIndex="6"/>
|
||||||
<TextBox x:Name="calcIPRange" HorizontalAlignment="Left" Height="24" Margin="258,323,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336"/>
|
<TextBox x:Name="calcIPRange" HorizontalAlignment="Left" Height="24" Margin="258,323,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336" TabIndex="7"/>
|
||||||
<TextBox x:Name="clacMaxNetCount" HorizontalAlignment="Left" Height="24" Margin="258,352,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336"/>
|
<TextBox x:Name="clacMaxNetCount" HorizontalAlignment="Left" Height="24" Margin="258,352,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336" TabIndex="8"/>
|
||||||
<TextBox x:Name="nextNumOfHosts" HorizontalAlignment="Left" Height="24" Margin="258,381,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="70"/>
|
<TextBox x:Name="nextNumOfHosts" HorizontalAlignment="Left" Height="24" Margin="258,381,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="70" TabIndex="9"/>
|
||||||
<Label x:Name="noticeLabel" Content="Label" HorizontalAlignment="Left" Margin="134,96,0,0" VerticalAlignment="Top" Height="54" Width="460"/>
|
<Label x:Name="noticeLabel" Content="Label" HorizontalAlignment="Left" Margin="134,96,0,0" VerticalAlignment="Top" Height="54" Width="460"/>
|
||||||
<Label Content="Maximum number of Hosts:" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="10,236,0,0" VerticalAlignment="Top" Width="228" Height="24"/>
|
<Label Content="Maximum number of Hosts:" HorizontalContentAlignment="Right" HorizontalAlignment="Left" Margin="10,236,0,0" VerticalAlignment="Top" Width="228" Height="24"/>
|
||||||
<Label Content="Network:" HorizontalAlignment="Left" HorizontalContentAlignment="Right" Margin="10,265,0,0" VerticalAlignment="Top" Width="228" Height="24"/>
|
<Label Content="Network:" HorizontalAlignment="Left" HorizontalContentAlignment="Right" Margin="10,265,0,0" VerticalAlignment="Top" Width="228" Height="24"/>
|
||||||
@@ -30,9 +30,9 @@
|
|||||||
<Label Content="IP:" HorizontalAlignment="Left" HorizontalContentAlignment="Right" Margin="10,55,0,0" VerticalAlignment="Top" Height="28" Width="24"/>
|
<Label Content="IP:" HorizontalAlignment="Left" HorizontalContentAlignment="Right" Margin="10,55,0,0" VerticalAlignment="Top" Height="28" Width="24"/>
|
||||||
<Label Content="Network-Type:" HorizontalAlignment="Left" HorizontalContentAlignment="Right" Margin="238,58,0,0" VerticalAlignment="Top" Width="90" Height="24"/>
|
<Label Content="Network-Type:" HorizontalAlignment="Left" HorizontalContentAlignment="Right" Margin="238,58,0,0" VerticalAlignment="Top" Width="90" Height="24"/>
|
||||||
<Button Content="Show next subnet with this number of hosts" x:Name="btnNextSubnet" HorizontalAlignment="Left" Margin="333,383,0,0" VerticalAlignment="Top" Width="261" Click="btnNextSubnet_Click"/>
|
<Button Content="Show next subnet with this number of hosts" x:Name="btnNextSubnet" HorizontalAlignment="Left" Margin="333,383,0,0" VerticalAlignment="Top" Width="261" Click="btnNextSubnet_Click"/>
|
||||||
<TextBox x:Name="tbIPAddressP2" Text="255" HorizontalAlignment="Left" Height="23" Margin="72,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" />
|
<TextBox x:Name="tbIPAddressP2" Text="255" HorizontalAlignment="Left" Height="23" Margin="72,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" TabIndex="1" />
|
||||||
<TextBox x:Name="tbIPAddressP3" Text="255" HorizontalAlignment="Left" Height="23" Margin="105,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" />
|
<TextBox x:Name="tbIPAddressP3" Text="255" HorizontalAlignment="Left" Height="23" Margin="105,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" TabIndex="2" />
|
||||||
<TextBox x:Name="tbIPAddressP4" Text="255" HorizontalAlignment="Left" Height="23" Margin="138,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" />
|
<TextBox x:Name="tbIPAddressP4" Text="255" HorizontalAlignment="Left" Height="23" Margin="138,58,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="28" KeyDown="ipAddress_KeyDown" TabIndex="3" />
|
||||||
<Label Content=".
|
<Label Content=".
|
||||||
" HorizontalAlignment="Left" Margin="68,59,0,0" Padding="0" VerticalAlignment="Top" Width="3"/>
|
" HorizontalAlignment="Left" Margin="68,59,0,0" Padding="0" VerticalAlignment="Top" Width="3"/>
|
||||||
<Label Content=". " HorizontalAlignment="Left" Margin="101,59,0,0" Padding="0" VerticalAlignment="Top" Width="3"/>
|
<Label Content=". " HorizontalAlignment="Left" Margin="101,59,0,0" Padding="0" VerticalAlignment="Top" Width="3"/>
|
||||||
@@ -15,37 +15,23 @@ using System.Windows.Shapes;
|
|||||||
using NetCalc;
|
using NetCalc;
|
||||||
using PTConverter.Plugin;
|
using PTConverter.Plugin;
|
||||||
|
|
||||||
namespace Networking
|
namespace Networking.Pages
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaktionslogik für Networking.xaml
|
/// Interaktionslogik für Networking.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class Networking_IPv4 : UserControl, IPlugin, IPage
|
public partial class IPv4 : UserControl, IPage
|
||||||
{
|
{
|
||||||
#region Declarations
|
#region Declarations
|
||||||
protected IPTool ip = null;
|
protected IPTool ip = null;
|
||||||
protected bool fill = false; // lock events wenn updating
|
protected bool fill = false; // lock events wenn updating
|
||||||
protected bool isIP = false;
|
protected bool isIP = false;
|
||||||
|
|
||||||
public string Author => "Kevin Krüger";
|
|
||||||
|
|
||||||
public string Company => "PeaceToke";
|
|
||||||
|
|
||||||
public string PluginName => "Networking";
|
|
||||||
|
|
||||||
public string Description => "Calculate networks very easy!";
|
|
||||||
|
|
||||||
public string Version => "1.0.0";
|
|
||||||
|
|
||||||
public string IconLink => "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.clipartmax.com%2Fpng%2Fmiddle%2F276-2769230_networking-deep-neural-network-icon.png&f=1&nofb=1";
|
|
||||||
|
|
||||||
public IPage Page => this;
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private string _ipAddress = "0.0.0.0";
|
private string _ipAddress = "0.0.0.0";
|
||||||
private string IPAddress { get => tbIPAddressP1.Text + "." + tbIPAddressP2.Text + "." + tbIPAddressP3.Text + "." + tbIPAddressP4.Text; set => _ipAddress = value; }
|
private string IPAddress { get => tbIPAddressP1.Text + "." + tbIPAddressP2.Text + "." + tbIPAddressP3.Text + "." + tbIPAddressP4.Text; set => _ipAddress = value; }
|
||||||
|
|
||||||
public Networking_IPv4()
|
public IPv4()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
@@ -61,7 +47,7 @@ namespace Networking
|
|||||||
}
|
}
|
||||||
public string GetCategory() => "Networking";
|
public string GetCategory() => "Networking";
|
||||||
public string GetUnderCategory() => "IPv4";
|
public string GetUnderCategory() => "IPv4";
|
||||||
public UserControl GetPage() => new Networking_IPv4();
|
public UserControl GetPage() => new IPv4();
|
||||||
|
|
||||||
#region Methods Used
|
#region Methods Used
|
||||||
protected void newIP()
|
protected void newIP()
|
||||||
14
Networking/Pages/PortScanner.xaml
Normal file
14
Networking/Pages/PortScanner.xaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<UserControl x:Class="Networking.Pages.PortScanner"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Networking.Pages"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800" Background="White">
|
||||||
|
<Grid>
|
||||||
|
<WindowsFormsHost>
|
||||||
|
<local:WF_PortScanner/>
|
||||||
|
</WindowsFormsHost>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
35
Networking/Pages/PortScanner.xaml.cs
Normal file
35
Networking/Pages/PortScanner.xaml.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using PTConverter.Plugin;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Networking.Pages
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für PortScanner.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class PortScanner : UserControl, IPage
|
||||||
|
{
|
||||||
|
public PortScanner()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetCategory() => "Networking";
|
||||||
|
|
||||||
|
public UserControl GetPage() => new PortScanner();
|
||||||
|
|
||||||
|
public string GetUnderCategory() => "PortScanner";
|
||||||
|
}
|
||||||
|
}
|
||||||
137
Networking/Pages/WF_IPScanner.Designer.cs
generated
Normal file
137
Networking/Pages/WF_IPScanner.Designer.cs
generated
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
|
||||||
|
namespace Networking.Pages
|
||||||
|
{
|
||||||
|
partial class WF_IPScanner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Erforderliche Designervariable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verwendete Ressourcen bereinigen.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Vom Komponenten-Designer generierter Code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Erforderliche Methode für die Designerunterstützung.
|
||||||
|
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.lvIPList = new System.Windows.Forms.ListView();
|
||||||
|
this.chIP = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.chPing = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.chHost = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.chRecognized = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.btnScan = new System.Windows.Forms.Button();
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.tbIPRange = new System.Windows.Forms.TextBox();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// lvIPList
|
||||||
|
//
|
||||||
|
this.lvIPList.Activation = System.Windows.Forms.ItemActivation.OneClick;
|
||||||
|
this.lvIPList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.lvIPList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||||
|
this.chIP,
|
||||||
|
this.chPing,
|
||||||
|
this.chHost,
|
||||||
|
this.chRecognized});
|
||||||
|
this.lvIPList.FullRowSelect = true;
|
||||||
|
this.lvIPList.GridLines = true;
|
||||||
|
this.lvIPList.HideSelection = false;
|
||||||
|
this.lvIPList.HoverSelection = true;
|
||||||
|
this.lvIPList.Location = new System.Drawing.Point(0, 32);
|
||||||
|
this.lvIPList.MultiSelect = false;
|
||||||
|
this.lvIPList.Name = "lvIPList";
|
||||||
|
this.lvIPList.RightToLeft = System.Windows.Forms.RightToLeft.No;
|
||||||
|
this.lvIPList.Size = new System.Drawing.Size(800, 418);
|
||||||
|
this.lvIPList.TabIndex = 1;
|
||||||
|
this.lvIPList.UseCompatibleStateImageBehavior = false;
|
||||||
|
this.lvIPList.View = System.Windows.Forms.View.Details;
|
||||||
|
//
|
||||||
|
// chIP
|
||||||
|
//
|
||||||
|
this.chIP.Text = "IP";
|
||||||
|
this.chIP.Width = 191;
|
||||||
|
//
|
||||||
|
// chPing
|
||||||
|
//
|
||||||
|
this.chPing.Text = "Ping";
|
||||||
|
//
|
||||||
|
// chHost
|
||||||
|
//
|
||||||
|
this.chHost.Text = "Host";
|
||||||
|
this.chHost.Width = 241;
|
||||||
|
//
|
||||||
|
// chRecognized
|
||||||
|
//
|
||||||
|
this.chRecognized.Text = "Recognized as";
|
||||||
|
this.chRecognized.Width = 296;
|
||||||
|
//
|
||||||
|
// btnScan
|
||||||
|
//
|
||||||
|
this.btnScan.Location = new System.Drawing.Point(319, 4);
|
||||||
|
this.btnScan.Name = "btnScan";
|
||||||
|
this.btnScan.Size = new System.Drawing.Size(112, 23);
|
||||||
|
this.btnScan.TabIndex = 7;
|
||||||
|
this.btnScan.Text = "Scan";
|
||||||
|
this.btnScan.UseVisualStyleBackColor = true;
|
||||||
|
this.btnScan.Click += new System.EventHandler(this.btnScan_Click);
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Location = new System.Drawing.Point(5, 9);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(50, 13);
|
||||||
|
this.label1.TabIndex = 6;
|
||||||
|
this.label1.Text = "IP range:";
|
||||||
|
//
|
||||||
|
// tbIPRange
|
||||||
|
//
|
||||||
|
this.tbIPRange.Location = new System.Drawing.Point(62, 6);
|
||||||
|
this.tbIPRange.Name = "tbIPRange";
|
||||||
|
this.tbIPRange.Size = new System.Drawing.Size(251, 20);
|
||||||
|
this.tbIPRange.TabIndex = 8;
|
||||||
|
//
|
||||||
|
// WF_IPScanner
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.tbIPRange);
|
||||||
|
this.Controls.Add(this.btnScan);
|
||||||
|
this.Controls.Add(this.label1);
|
||||||
|
this.Controls.Add(this.lvIPList);
|
||||||
|
this.Name = "WF_IPScanner";
|
||||||
|
this.Size = new System.Drawing.Size(800, 450);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.ListView lvIPList;
|
||||||
|
private System.Windows.Forms.ColumnHeader chIP;
|
||||||
|
private System.Windows.Forms.ColumnHeader chPing;
|
||||||
|
private System.Windows.Forms.ColumnHeader chHost;
|
||||||
|
private System.Windows.Forms.ColumnHeader chRecognized;
|
||||||
|
private System.Windows.Forms.Button btnScan;
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.TextBox tbIPRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
110
Networking/Pages/WF_IPScanner.cs
Normal file
110
Networking/Pages/WF_IPScanner.cs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
using IPScanner;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Networking.Pages
|
||||||
|
{
|
||||||
|
public partial class WF_IPScanner : UserControl
|
||||||
|
{
|
||||||
|
NetworkScanner scanner = new NetworkScanner();
|
||||||
|
Timer timer = new Timer();
|
||||||
|
List<IPScanResult> results;
|
||||||
|
public WF_IPScanner()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
List<Tuple<IPAddress, IPAddress>> ipRanges = IPRanges.GetOperationalIPRanges();
|
||||||
|
if (ipRanges.Count > 0)
|
||||||
|
{
|
||||||
|
//tbIPRange.Text = ipRanges[0].Item1.GetAddressBytes().ToString();
|
||||||
|
tbIPRange.Text = IPtoString(ipRanges[0].Item1.GetAddressBytes()) + "-" + ipRanges[0].Item2.GetAddressBytes()[3].ToString();
|
||||||
|
// ipTo.IPAddress = ipRanges[0].Item2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string IPtoString(byte[] array)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Concatenate all the elements into a StringBuilder.
|
||||||
|
//
|
||||||
|
StringBuilder strinbuilder = new StringBuilder();
|
||||||
|
for (int i = 0; i < array.Count(); i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
strinbuilder.Append(array[i]);
|
||||||
|
if (i != array.Count() - 1)
|
||||||
|
strinbuilder.Append('.');
|
||||||
|
}
|
||||||
|
return strinbuilder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetPingTime(IPScanResult result)
|
||||||
|
{
|
||||||
|
if (result.ping > -1)
|
||||||
|
return result.ping + " ms";
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulateListView()
|
||||||
|
{
|
||||||
|
bool itemModified = false;
|
||||||
|
for (int i = 0; i < results.Count; i++)
|
||||||
|
{
|
||||||
|
IPScanResult result = results[i];
|
||||||
|
if (result.status == ScanStatus.Complete || result.status == ScanStatus.Partial)
|
||||||
|
{
|
||||||
|
string ip = result.ip.ToString();
|
||||||
|
ListViewItem[] matchedItems = lvIPList.Items.Find(ip, false);
|
||||||
|
if (matchedItems.Length > 0)
|
||||||
|
{
|
||||||
|
matchedItems[0].Tag = result.response;
|
||||||
|
matchedItems[0].SubItems[0].Text = result.ip.ToString();
|
||||||
|
matchedItems[0].SubItems[1].Text = GetPingTime(result);
|
||||||
|
matchedItems[0].SubItems[2].Text = result.host;
|
||||||
|
matchedItems[0].SubItems[3].Text = result.identification;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ListViewItem lvi = new ListViewItem(new string[] { result.ip.ToString(), GetPingTime(result), result.host, result.identification });
|
||||||
|
lvi.Name = ip;
|
||||||
|
lvIPList.Items.Add(lvi);
|
||||||
|
}
|
||||||
|
itemModified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void timer_Tick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
PopulateListView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnScan_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
timer.Stop();
|
||||||
|
lvIPList.Items.Clear();
|
||||||
|
|
||||||
|
IPAddress ipFrom = IPAddress.Parse(tbIPRange.Text.Split(new Char[] { '-' })[0]);
|
||||||
|
|
||||||
|
IPAddress ipTo = IPAddress.Parse(ipFrom.GetAddressBytes()[0] + "." +
|
||||||
|
ipFrom.GetAddressBytes()[1] + "." +
|
||||||
|
ipFrom.GetAddressBytes()[2] + "." +
|
||||||
|
(tbIPRange.Text.Contains("-") ? byte.Parse(tbIPRange.Text.Split(new Char[] { '-' })[1].ToString()) : ipFrom.GetAddressBytes()[3]));
|
||||||
|
|
||||||
|
results = scanner.BeginScan(ipFrom, ipTo);
|
||||||
|
timer.Interval = 1000;
|
||||||
|
timer.Tick += timer_Tick;
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
Networking/Pages/WF_IPScanner.resx
Normal file
120
Networking/Pages/WF_IPScanner.resx
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
281
Networking/Pages/WF_PortScanner.Designer.cs
generated
Normal file
281
Networking/Pages/WF_PortScanner.Designer.cs
generated
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
namespace Networking.Pages
|
||||||
|
{
|
||||||
|
partial class WF_PortScanner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Erforderliche Designervariable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verwendete Ressourcen bereinigen.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Vom Komponenten-Designer generierter Code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Erforderliche Methode für die Designerunterstützung.
|
||||||
|
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.hostnameTextBox = new System.Windows.Forms.TextBox();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.modeGroupBox = new System.Windows.Forms.GroupBox();
|
||||||
|
this.udpModeRadioButton = new System.Windows.Forms.RadioButton();
|
||||||
|
this.tcpModeRadioButton = new System.Windows.Forms.RadioButton();
|
||||||
|
this.portRangeCheckBox = new System.Windows.Forms.CheckBox();
|
||||||
|
this.portTextBoxMax = new System.Windows.Forms.TextBox();
|
||||||
|
this.dashLabel = new System.Windows.Forms.Label();
|
||||||
|
this.portTextBoxMin = new System.Windows.Forms.TextBox();
|
||||||
|
this.portLabel = new System.Windows.Forms.Label();
|
||||||
|
this.timeoutGroupBox = new System.Windows.Forms.GroupBox();
|
||||||
|
this.timeoutComboBox = new System.Windows.Forms.ComboBox();
|
||||||
|
this.checkPortButton = new System.Windows.Forms.Button();
|
||||||
|
this.listview1 = new System.Windows.Forms.ListView();
|
||||||
|
this.chPort = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.chStatus = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||||
|
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||||
|
this.cancelButton = new System.Windows.Forms.Button();
|
||||||
|
this.modeGroupBox.SuspendLayout();
|
||||||
|
this.timeoutGroupBox.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// hostnameTextBox
|
||||||
|
//
|
||||||
|
this.hostnameTextBox.Location = new System.Drawing.Point(38, 24);
|
||||||
|
this.hostnameTextBox.Name = "hostnameTextBox";
|
||||||
|
this.hostnameTextBox.Size = new System.Drawing.Size(251, 20);
|
||||||
|
this.hostnameTextBox.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(5, 27);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(29, 13);
|
||||||
|
this.label3.TabIndex = 5;
|
||||||
|
this.label3.Text = "Host";
|
||||||
|
//
|
||||||
|
// modeGroupBox
|
||||||
|
//
|
||||||
|
this.modeGroupBox.Controls.Add(this.udpModeRadioButton);
|
||||||
|
this.modeGroupBox.Controls.Add(this.tcpModeRadioButton);
|
||||||
|
this.modeGroupBox.Location = new System.Drawing.Point(296, 19);
|
||||||
|
this.modeGroupBox.Name = "modeGroupBox";
|
||||||
|
this.modeGroupBox.Size = new System.Drawing.Size(111, 57);
|
||||||
|
this.modeGroupBox.TabIndex = 13;
|
||||||
|
this.modeGroupBox.TabStop = false;
|
||||||
|
this.modeGroupBox.Text = "Mode";
|
||||||
|
//
|
||||||
|
// udpModeRadioButton
|
||||||
|
//
|
||||||
|
this.udpModeRadioButton.AutoSize = true;
|
||||||
|
this.udpModeRadioButton.Location = new System.Drawing.Point(13, 35);
|
||||||
|
this.udpModeRadioButton.Name = "udpModeRadioButton";
|
||||||
|
this.udpModeRadioButton.Size = new System.Drawing.Size(48, 17);
|
||||||
|
this.udpModeRadioButton.TabIndex = 11;
|
||||||
|
this.udpModeRadioButton.Text = "UDP";
|
||||||
|
this.udpModeRadioButton.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// tcpModeRadioButton
|
||||||
|
//
|
||||||
|
this.tcpModeRadioButton.AutoSize = true;
|
||||||
|
this.tcpModeRadioButton.Checked = true;
|
||||||
|
this.tcpModeRadioButton.Location = new System.Drawing.Point(13, 16);
|
||||||
|
this.tcpModeRadioButton.Name = "tcpModeRadioButton";
|
||||||
|
this.tcpModeRadioButton.Size = new System.Drawing.Size(46, 17);
|
||||||
|
this.tcpModeRadioButton.TabIndex = 10;
|
||||||
|
this.tcpModeRadioButton.TabStop = true;
|
||||||
|
this.tcpModeRadioButton.Text = "TCP";
|
||||||
|
this.tcpModeRadioButton.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// portRangeCheckBox
|
||||||
|
//
|
||||||
|
this.portRangeCheckBox.AutoSize = true;
|
||||||
|
this.portRangeCheckBox.Location = new System.Drawing.Point(156, 57);
|
||||||
|
this.portRangeCheckBox.Name = "portRangeCheckBox";
|
||||||
|
this.portRangeCheckBox.Size = new System.Drawing.Size(80, 17);
|
||||||
|
this.portRangeCheckBox.TabIndex = 19;
|
||||||
|
this.portRangeCheckBox.Text = "Port Range";
|
||||||
|
this.portRangeCheckBox.UseVisualStyleBackColor = true;
|
||||||
|
this.portRangeCheckBox.CheckedChanged += new System.EventHandler(this.portRangeCheckBox_CheckedChanged);
|
||||||
|
//
|
||||||
|
// portTextBoxMax
|
||||||
|
//
|
||||||
|
this.portTextBoxMax.Enabled = false;
|
||||||
|
this.portTextBoxMax.Location = new System.Drawing.Point(98, 55);
|
||||||
|
this.portTextBoxMax.MaxLength = 5;
|
||||||
|
this.portTextBoxMax.Name = "portTextBoxMax";
|
||||||
|
this.portTextBoxMax.Size = new System.Drawing.Size(38, 20);
|
||||||
|
this.portTextBoxMax.TabIndex = 18;
|
||||||
|
//
|
||||||
|
// dashLabel
|
||||||
|
//
|
||||||
|
this.dashLabel.AutoSize = true;
|
||||||
|
this.dashLabel.Location = new System.Drawing.Point(82, 58);
|
||||||
|
this.dashLabel.Name = "dashLabel";
|
||||||
|
this.dashLabel.Size = new System.Drawing.Size(10, 13);
|
||||||
|
this.dashLabel.TabIndex = 17;
|
||||||
|
this.dashLabel.Text = "-";
|
||||||
|
//
|
||||||
|
// portTextBoxMin
|
||||||
|
//
|
||||||
|
this.portTextBoxMin.Location = new System.Drawing.Point(38, 55);
|
||||||
|
this.portTextBoxMin.MaxLength = 5;
|
||||||
|
this.portTextBoxMin.Name = "portTextBoxMin";
|
||||||
|
this.portTextBoxMin.Size = new System.Drawing.Size(38, 20);
|
||||||
|
this.portTextBoxMin.TabIndex = 16;
|
||||||
|
//
|
||||||
|
// portLabel
|
||||||
|
//
|
||||||
|
this.portLabel.AutoSize = true;
|
||||||
|
this.portLabel.Location = new System.Drawing.Point(3, 58);
|
||||||
|
this.portLabel.Name = "portLabel";
|
||||||
|
this.portLabel.Size = new System.Drawing.Size(31, 13);
|
||||||
|
this.portLabel.TabIndex = 15;
|
||||||
|
this.portLabel.Text = "Ports";
|
||||||
|
//
|
||||||
|
// timeoutGroupBox
|
||||||
|
//
|
||||||
|
this.timeoutGroupBox.Controls.Add(this.timeoutComboBox);
|
||||||
|
this.timeoutGroupBox.Location = new System.Drawing.Point(413, 24);
|
||||||
|
this.timeoutGroupBox.Name = "timeoutGroupBox";
|
||||||
|
this.timeoutGroupBox.Size = new System.Drawing.Size(110, 52);
|
||||||
|
this.timeoutGroupBox.TabIndex = 20;
|
||||||
|
this.timeoutGroupBox.TabStop = false;
|
||||||
|
this.timeoutGroupBox.Text = "Timeout";
|
||||||
|
//
|
||||||
|
// timeoutComboBox
|
||||||
|
//
|
||||||
|
this.timeoutComboBox.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
|
||||||
|
this.timeoutComboBox.FormattingEnabled = true;
|
||||||
|
this.timeoutComboBox.Items.AddRange(new object[] {
|
||||||
|
"500 ms",
|
||||||
|
"1000 ms",
|
||||||
|
"1500 ms",
|
||||||
|
"2000 ms"});
|
||||||
|
this.timeoutComboBox.Location = new System.Drawing.Point(6, 21);
|
||||||
|
this.timeoutComboBox.Name = "timeoutComboBox";
|
||||||
|
this.timeoutComboBox.Size = new System.Drawing.Size(98, 21);
|
||||||
|
this.timeoutComboBox.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// checkPortButton
|
||||||
|
//
|
||||||
|
this.checkPortButton.Location = new System.Drawing.Point(529, 21);
|
||||||
|
this.checkPortButton.Name = "checkPortButton";
|
||||||
|
this.checkPortButton.Size = new System.Drawing.Size(105, 31);
|
||||||
|
this.checkPortButton.TabIndex = 5;
|
||||||
|
this.checkPortButton.Text = "Scan";
|
||||||
|
this.checkPortButton.UseVisualStyleBackColor = true;
|
||||||
|
this.checkPortButton.Click += new System.EventHandler(this.checkPortButton_Click);
|
||||||
|
//
|
||||||
|
// listview1
|
||||||
|
//
|
||||||
|
this.listview1.Activation = System.Windows.Forms.ItemActivation.OneClick;
|
||||||
|
this.listview1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.listview1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||||
|
this.chPort,
|
||||||
|
this.chStatus});
|
||||||
|
this.listview1.FullRowSelect = true;
|
||||||
|
this.listview1.GridLines = true;
|
||||||
|
this.listview1.HideSelection = false;
|
||||||
|
this.listview1.HoverSelection = true;
|
||||||
|
this.listview1.Location = new System.Drawing.Point(0, 89);
|
||||||
|
this.listview1.MultiSelect = false;
|
||||||
|
this.listview1.Name = "listview1";
|
||||||
|
this.listview1.RightToLeft = System.Windows.Forms.RightToLeft.No;
|
||||||
|
this.listview1.Size = new System.Drawing.Size(800, 361);
|
||||||
|
this.listview1.TabIndex = 21;
|
||||||
|
this.listview1.UseCompatibleStateImageBehavior = false;
|
||||||
|
this.listview1.View = System.Windows.Forms.View.Details;
|
||||||
|
//
|
||||||
|
// chPort
|
||||||
|
//
|
||||||
|
this.chPort.Text = "Port";
|
||||||
|
this.chPort.Width = 191;
|
||||||
|
//
|
||||||
|
// chStatus
|
||||||
|
//
|
||||||
|
this.chStatus.Text = "Status";
|
||||||
|
this.chStatus.Width = 296;
|
||||||
|
//
|
||||||
|
// progressBar1
|
||||||
|
//
|
||||||
|
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.progressBar1.Location = new System.Drawing.Point(0, 79);
|
||||||
|
this.progressBar1.Name = "progressBar1";
|
||||||
|
this.progressBar1.Size = new System.Drawing.Size(800, 10);
|
||||||
|
this.progressBar1.TabIndex = 22;
|
||||||
|
//
|
||||||
|
// cancelButton
|
||||||
|
//
|
||||||
|
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||||
|
this.cancelButton.Location = new System.Drawing.Point(529, 52);
|
||||||
|
this.cancelButton.Name = "cancelButton";
|
||||||
|
this.cancelButton.Size = new System.Drawing.Size(105, 23);
|
||||||
|
this.cancelButton.TabIndex = 23;
|
||||||
|
this.cancelButton.Text = "Cancel";
|
||||||
|
this.cancelButton.UseVisualStyleBackColor = true;
|
||||||
|
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
|
||||||
|
//
|
||||||
|
// WF_PortScanner
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.cancelButton);
|
||||||
|
this.Controls.Add(this.progressBar1);
|
||||||
|
this.Controls.Add(this.listview1);
|
||||||
|
this.Controls.Add(this.checkPortButton);
|
||||||
|
this.Controls.Add(this.timeoutGroupBox);
|
||||||
|
this.Controls.Add(this.portRangeCheckBox);
|
||||||
|
this.Controls.Add(this.portTextBoxMax);
|
||||||
|
this.Controls.Add(this.dashLabel);
|
||||||
|
this.Controls.Add(this.portTextBoxMin);
|
||||||
|
this.Controls.Add(this.portLabel);
|
||||||
|
this.Controls.Add(this.modeGroupBox);
|
||||||
|
this.Controls.Add(this.label3);
|
||||||
|
this.Controls.Add(this.hostnameTextBox);
|
||||||
|
this.Name = "WF_PortScanner";
|
||||||
|
this.Size = new System.Drawing.Size(800, 450);
|
||||||
|
this.modeGroupBox.ResumeLayout(false);
|
||||||
|
this.modeGroupBox.PerformLayout();
|
||||||
|
this.timeoutGroupBox.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
private System.Windows.Forms.TextBox hostnameTextBox;
|
||||||
|
private System.Windows.Forms.Label label3;
|
||||||
|
private System.Windows.Forms.GroupBox modeGroupBox;
|
||||||
|
private System.Windows.Forms.RadioButton udpModeRadioButton;
|
||||||
|
private System.Windows.Forms.RadioButton tcpModeRadioButton;
|
||||||
|
private System.Windows.Forms.CheckBox portRangeCheckBox;
|
||||||
|
private System.Windows.Forms.TextBox portTextBoxMax;
|
||||||
|
private System.Windows.Forms.Label dashLabel;
|
||||||
|
private System.Windows.Forms.TextBox portTextBoxMin;
|
||||||
|
private System.Windows.Forms.Label portLabel;
|
||||||
|
private System.Windows.Forms.GroupBox timeoutGroupBox;
|
||||||
|
private System.Windows.Forms.ComboBox timeoutComboBox;
|
||||||
|
private System.Windows.Forms.Button checkPortButton;
|
||||||
|
private System.Windows.Forms.ListView listview1;
|
||||||
|
private System.Windows.Forms.ColumnHeader chPort;
|
||||||
|
private System.Windows.Forms.ColumnHeader chStatus;
|
||||||
|
private System.Windows.Forms.ProgressBar progressBar1;
|
||||||
|
private System.Windows.Forms.Button cancelButton;
|
||||||
|
}
|
||||||
|
}
|
||||||
271
Networking/Pages/WF_PortScanner.cs
Normal file
271
Networking/Pages/WF_PortScanner.cs
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
using PortScanner;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Networking.Pages
|
||||||
|
{
|
||||||
|
public partial class WF_PortScanner : UserControl
|
||||||
|
{
|
||||||
|
// Delegate to report back with one open port
|
||||||
|
public delegate void ExecuteOnceCallback(int openPort);
|
||||||
|
|
||||||
|
// Delegate to report back with one open port (Async)
|
||||||
|
public delegate void ExecuteOnceAsyncCallback(int port, bool isOpen, bool isCancelled, bool isLast);
|
||||||
|
|
||||||
|
// The manager instance
|
||||||
|
IScannerManagerSingleton smc;
|
||||||
|
|
||||||
|
// Cancellation token source for the cancel button
|
||||||
|
private CancellationTokenSource cts;
|
||||||
|
|
||||||
|
// Current mode of operation
|
||||||
|
private ScannerManagerSingleton.ScanMode currentScanMode;
|
||||||
|
|
||||||
|
public WF_PortScanner()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Load += WF_PortScanner_Load;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WF_PortScanner_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// Get the ScannerManagerSingleton instance
|
||||||
|
smc = ScannerManagerSingleton.Instance;
|
||||||
|
|
||||||
|
// Populate the timeout times list box
|
||||||
|
PopulateTimeoutListBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulateTimeoutListBox()
|
||||||
|
{
|
||||||
|
// Assign the list to the ComboBox's DataSource property
|
||||||
|
timeoutComboBox.DataSource = TimeoutListItem.CreateTimeoutListItems();
|
||||||
|
timeoutComboBox.DisplayMember = "DisplayMember";
|
||||||
|
timeoutComboBox.ValueMember = "ValueMember";
|
||||||
|
|
||||||
|
// Set default value
|
||||||
|
timeoutComboBox.SelectedValue = 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method is used as a callback for portscanning - writes to the log box (text box)
|
||||||
|
public void PortResult(int port, bool isOpen, bool isCancelled, bool isLast)
|
||||||
|
{
|
||||||
|
string status;
|
||||||
|
|
||||||
|
// The operation has been cancelled by MainWindow
|
||||||
|
if (isCancelled)
|
||||||
|
{
|
||||||
|
status = "Operation cancelled." + Environment.NewLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The port is open
|
||||||
|
else if (isOpen)
|
||||||
|
{
|
||||||
|
//status = String.Format("{0}, {1} port {2} is open.{3}", hostnameTextBox.Text, currentScanMode.ToString(), port, Environment.NewLine);
|
||||||
|
var item = new ListViewItem(new[] { port.ToString(), "Open" });
|
||||||
|
listview1.Items.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The port is closed
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = String.Format("{0}, {1} port {2} is closed.{3}", hostnameTextBox.Text, currentScanMode.ToString(), port, Environment.NewLine);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isLast || isCancelled)
|
||||||
|
ToggleInputs(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether the timeout combo box has user input or not
|
||||||
|
private bool IsTimeoutComboBoxUserInput()
|
||||||
|
{
|
||||||
|
var inputText = timeoutComboBox.Text;
|
||||||
|
|
||||||
|
foreach (var displayMemberText in (List<TimeoutListItem>)timeoutComboBox.DataSource)
|
||||||
|
{
|
||||||
|
if (displayMemberText.DisplayMember == inputText)
|
||||||
|
{
|
||||||
|
// Select the one that's in the box's list to prevent some problems
|
||||||
|
// This will return because the user input IS in the combo box's DataSource
|
||||||
|
// However it is still user input and does not have a ValueMember. Exception
|
||||||
|
// will be thrown.
|
||||||
|
timeoutComboBox.SelectedItem = displayMemberText;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Executed when the Check Port button is clicked
|
||||||
|
private void checkPortButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
listview1.Items.Clear();
|
||||||
|
|
||||||
|
// Get user inputs
|
||||||
|
string hostname = hostnameTextBox.Text;
|
||||||
|
if (hostname == "")
|
||||||
|
{
|
||||||
|
MessageBox.Show("Please enter a valid hostname.",
|
||||||
|
"Input Error",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
hostnameTextBox.Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check port
|
||||||
|
int portMin = InputChecker.ParsePort(portTextBoxMin.Text);
|
||||||
|
if (portMin == -1)
|
||||||
|
{
|
||||||
|
MessageBox.Show((portRangeCheckBox.Checked ? "Lower limit of port range" : "Port") + " invalid.",
|
||||||
|
"Input Error",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
portTextBoxMin.Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get scan mode
|
||||||
|
ScannerManagerSingleton.ScanMode scanMode = ReadScanMode();
|
||||||
|
|
||||||
|
// If custom timeout time, verify correct user input
|
||||||
|
int timeout;
|
||||||
|
if (IsTimeoutComboBoxUserInput())
|
||||||
|
{
|
||||||
|
// If valid, proceed with that input as timeout
|
||||||
|
timeout = InputChecker.ParseTimeout(timeoutComboBox.Text);
|
||||||
|
if (timeout == -1)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Timeout format: [time], [time]ms or [time] ms.\nTimeout must be between 250 ms and 20000 ms.",
|
||||||
|
"Timeout Error",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Else, use the ValueMember of the selected Member
|
||||||
|
timeout = (int)timeoutComboBox.SelectedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate CTS
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
// Simple one port check
|
||||||
|
if (!portRangeCheckBox.Checked)
|
||||||
|
{
|
||||||
|
// The callback for scan result
|
||||||
|
var callback = new ExecuteOnceAsyncCallback(PortResult);
|
||||||
|
|
||||||
|
// Send one check request and toggle user inputs
|
||||||
|
ToggleInputs(false);
|
||||||
|
smc.ExecuteOnceAsync(hostname, portMin, timeout, scanMode, callback, cts.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Port range check
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Verify input
|
||||||
|
int portMax = InputChecker.ParsePort(portTextBoxMax.Text);
|
||||||
|
if (portMax == -1)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Upper limit of port range invalid.",
|
||||||
|
"Input Error",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
portTextBoxMax.Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (portMax < portMin)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Port range invalid.",
|
||||||
|
"Input Error",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
portTextBoxMax.Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The callback for scan result
|
||||||
|
var callback = new ExecuteOnceAsyncCallback(PortResult);
|
||||||
|
|
||||||
|
// Set status box text
|
||||||
|
//var connectionText = String.Format("Connecting to {0}, port {1}...{2}", hostname, portMin,
|
||||||
|
// Environment.NewLine);
|
||||||
|
//statusTextBox.AppendText(connectionText);
|
||||||
|
//Logger.Info(connectionText);
|
||||||
|
// Toggle inputs and begin operation
|
||||||
|
ToggleInputs(false);
|
||||||
|
smc.ExecuteRangeAsync(hostname, portMin, portMax, timeout, scanMode,progressBar1, callback, cts.Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read scan mode radio button selection
|
||||||
|
private ScannerManagerSingleton.ScanMode ReadScanMode()
|
||||||
|
{
|
||||||
|
if (tcpModeRadioButton.Checked)
|
||||||
|
{
|
||||||
|
currentScanMode = ScannerManagerSingleton.ScanMode.TCP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentScanMode = ScannerManagerSingleton.ScanMode.UDP;
|
||||||
|
}
|
||||||
|
return currentScanMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void portRangeCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// This enables or disables the max. port input box
|
||||||
|
if (portRangeCheckBox.Checked)
|
||||||
|
{
|
||||||
|
portTextBoxMax.Enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
portTextBoxMax.Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle all inputs
|
||||||
|
private void ToggleInputs(bool setting)
|
||||||
|
{
|
||||||
|
hostnameTextBox.Enabled = setting;
|
||||||
|
portTextBoxMin.Enabled = setting;
|
||||||
|
checkPortButton.Enabled = setting;
|
||||||
|
portTextBoxMax.Enabled = setting;
|
||||||
|
portRangeCheckBox.Enabled = setting;
|
||||||
|
|
||||||
|
// Re-disable the portMax text box
|
||||||
|
if (!portRangeCheckBox.Checked)
|
||||||
|
{
|
||||||
|
portTextBoxMax.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set focus to hostnameTextBox
|
||||||
|
if (setting)
|
||||||
|
hostnameTextBox.Focus();
|
||||||
|
}
|
||||||
|
private void cancelButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// If cts is instantiated (i.e. the scanning operation is in progress, request cancellation
|
||||||
|
if (cts != null)
|
||||||
|
{
|
||||||
|
cts.Cancel();
|
||||||
|
progressBar1.Value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
Networking/Pages/WF_PortScanner.resx
Normal file
120
Networking/Pages/WF_PortScanner.resx
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
32
Networking/PluginInfo.cs
Normal file
32
Networking/PluginInfo.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Networking.Pages;
|
||||||
|
using PTConverter.Plugin;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Networking
|
||||||
|
{
|
||||||
|
public class PluginInfo : IPlugin
|
||||||
|
{
|
||||||
|
public string Author => "Kevin Krüger";
|
||||||
|
|
||||||
|
public string Company => "";
|
||||||
|
|
||||||
|
public string PluginName => "Networking";
|
||||||
|
|
||||||
|
public string Description => "This Plugin provides Network features.";
|
||||||
|
|
||||||
|
public string Version => "1.0.0";
|
||||||
|
|
||||||
|
public string IconLink => null;
|
||||||
|
|
||||||
|
public IEnumerable<IPage> RegisterPages => new List<IPage>()
|
||||||
|
{
|
||||||
|
{new IPv4() },
|
||||||
|
{new Pages.PortScanner() },
|
||||||
|
{new Pages.IPScanner() }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Networking/PortScanner/IScannerManagerSingleton.cs
Normal file
12
Networking/PortScanner/IScannerManagerSingleton.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Networking.Pages;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace PortScanner
|
||||||
|
{
|
||||||
|
internal interface IScannerManagerSingleton
|
||||||
|
{
|
||||||
|
void ExecuteOnceAsync(string hostname, int port, int timeout, ScannerManagerSingleton.ScanMode scanMode, WF_PortScanner.ExecuteOnceAsyncCallback callback, CancellationToken ct);
|
||||||
|
void ExecuteRangeAsync(string hostname, int portMin, int portMax, int timeout, ScannerManagerSingleton.ScanMode scanMode, ProgressBar progress, WF_PortScanner.ExecuteOnceAsyncCallback callback, CancellationToken ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
Networking/PortScanner/InputChecker.cs
Normal file
67
Networking/PortScanner/InputChecker.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PortScanner
|
||||||
|
{
|
||||||
|
static class InputChecker
|
||||||
|
{
|
||||||
|
// Check that a hostname string is valid
|
||||||
|
public static bool IsValidHostname(string hostname)
|
||||||
|
{
|
||||||
|
return hostname != "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that a port is valid - returns -1 if port is invalid
|
||||||
|
public static int ParsePort(string portString)
|
||||||
|
{
|
||||||
|
int port;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
port = Int32.Parse(portString);
|
||||||
|
}
|
||||||
|
// If any exception occurs, the string was not a proper port
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port < 1 || port > 65535)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that timeout combobox user input is valid...
|
||||||
|
// Accepted formats: [time] ms, [time]ms, [time]
|
||||||
|
public static int ParseTimeout(string timeoutString)
|
||||||
|
{
|
||||||
|
// The regex that is used for matching the input against
|
||||||
|
var regex = new Regex(@"^\d*\s*(ms)?$");
|
||||||
|
|
||||||
|
// Try matching the user input
|
||||||
|
if (!regex.IsMatch(timeoutString))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice off the "ms" part of the string
|
||||||
|
timeoutString = Regex.Match(timeoutString, @"\d+").Value;
|
||||||
|
int timeout = Int32.Parse(timeoutString);
|
||||||
|
|
||||||
|
// Doesn't work too well with a very short timeout period
|
||||||
|
if (timeout < 250 || timeout > 20000)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Networking/PortScanner/PortScannerBase.cs
Normal file
28
Networking/PortScanner/PortScannerBase.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
// This is the base class for all Port Scanners
|
||||||
|
namespace PortScanner
|
||||||
|
{
|
||||||
|
abstract class PortScannerBase
|
||||||
|
{
|
||||||
|
// Hostname and port properties for scanning
|
||||||
|
public string Hostname { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
|
||||||
|
// Timeout property that specifies how long to wait for an answer
|
||||||
|
public int Timeout { get; set; }
|
||||||
|
|
||||||
|
// Base construcor - just set up default values for properties
|
||||||
|
public PortScannerBase()
|
||||||
|
{
|
||||||
|
Hostname = "127.0.0.1";
|
||||||
|
Port = 22;
|
||||||
|
Timeout = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the hostname is listening on the port - asynchronously
|
||||||
|
public abstract Task<bool> CheckOpenAsync(CancellationToken ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
111
Networking/PortScanner/ScannerManagerSingleton.cs
Normal file
111
Networking/PortScanner/ScannerManagerSingleton.cs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
using Networking.Pages;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace PortScanner
|
||||||
|
{
|
||||||
|
public class ScannerManagerSingleton : IScannerManagerSingleton
|
||||||
|
{
|
||||||
|
// The instance variable - this is a singleton class
|
||||||
|
private static ScannerManagerSingleton _instance;
|
||||||
|
|
||||||
|
// The PortScanner used to scan ports
|
||||||
|
private PortScannerBase portScanner;
|
||||||
|
|
||||||
|
// Enumeration for scanning modes
|
||||||
|
public enum ScanMode
|
||||||
|
{
|
||||||
|
TCP = 1,
|
||||||
|
UDP = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private constructor - this is a singleton class
|
||||||
|
private ScannerManagerSingleton()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance property - this is a singleton class
|
||||||
|
public static ScannerManagerSingleton Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
_instance = new ScannerManagerSingleton();
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate the correct type of PortScanner
|
||||||
|
private void InstantiatePortScanner(ScanMode scanMode)
|
||||||
|
{
|
||||||
|
switch (scanMode)
|
||||||
|
{
|
||||||
|
case ScanMode.TCP:
|
||||||
|
portScanner = new TCPPortScanner();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ScanMode.UDP:
|
||||||
|
portScanner = new UDPPortScanner();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan one port asynchronously
|
||||||
|
public async void ExecuteOnceAsync(string hostname, int port, int timeout, ScanMode scanMode, WF_PortScanner.ExecuteOnceAsyncCallback callback, CancellationToken ct)
|
||||||
|
{
|
||||||
|
// Instantiate a PortScanner
|
||||||
|
InstantiatePortScanner(scanMode);
|
||||||
|
|
||||||
|
// Assign values
|
||||||
|
portScanner.Hostname = hostname;
|
||||||
|
portScanner.Port = port;
|
||||||
|
portScanner.Timeout = timeout;
|
||||||
|
|
||||||
|
// Await for the result of this operation
|
||||||
|
var task = portScanner.CheckOpenAsync(ct);
|
||||||
|
await task;
|
||||||
|
|
||||||
|
// If a cancellation request has been triggered through CancellationToken ct, we must advise the callback function
|
||||||
|
bool cancelled = ct.IsCancellationRequested;
|
||||||
|
|
||||||
|
// Callback with the result and the port
|
||||||
|
callback(port, task.Result, cancelled, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan a range of ports asynchronously
|
||||||
|
public async void ExecuteRangeAsync(string hostname, int portMin, int portMax, int timeout, ScanMode scanMode, ProgressBar progress, WF_PortScanner.ExecuteOnceAsyncCallback callback, CancellationToken ct)
|
||||||
|
{
|
||||||
|
// Instantiate a PortScanner
|
||||||
|
InstantiatePortScanner(scanMode);
|
||||||
|
|
||||||
|
// Assign first values
|
||||||
|
portScanner.Hostname = hostname;
|
||||||
|
portScanner.Timeout = timeout;
|
||||||
|
|
||||||
|
bool isLast = false;
|
||||||
|
bool cancelled = false;
|
||||||
|
|
||||||
|
for (int i = portMin; i <= portMax && !cancelled; i++)
|
||||||
|
{
|
||||||
|
if (i == portMax)
|
||||||
|
{
|
||||||
|
isLast = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
portScanner.Port = i;
|
||||||
|
int percent = 100 * i / portMax;
|
||||||
|
progress.Value = percent;
|
||||||
|
|
||||||
|
var task = portScanner.CheckOpenAsync(ct);
|
||||||
|
await task;
|
||||||
|
|
||||||
|
cancelled = ct.IsCancellationRequested;
|
||||||
|
|
||||||
|
callback(i, task.Result, cancelled, isLast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
28
Networking/PortScanner/Settings.cs
Normal file
28
Networking/PortScanner/Settings.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
namespace PortScanner.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
// This class allows you to handle specific events on the settings class:
|
||||||
|
// The SettingChanging event is raised before a setting's value is changed.
|
||||||
|
// The PropertyChanged event is raised after a setting's value is changed.
|
||||||
|
// The SettingsLoaded event is raised after the setting values are loaded.
|
||||||
|
// The SettingsSaving event is raised before the setting values are saved.
|
||||||
|
internal sealed partial class Settings {
|
||||||
|
|
||||||
|
public Settings() {
|
||||||
|
// // To add event handlers for saving and changing settings, uncomment the lines below:
|
||||||
|
//
|
||||||
|
// this.SettingChanging += this.SettingChangingEventHandler;
|
||||||
|
//
|
||||||
|
// this.SettingsSaving += this.SettingsSavingEventHandler;
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
|
||||||
|
// Add code to handle the SettingChangingEvent event here.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
|
||||||
|
// Add code to handle the SettingsSaving event here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
Networking/PortScanner/TCPPortScanner.cs
Normal file
56
Networking/PortScanner/TCPPortScanner.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PortScanner
|
||||||
|
{
|
||||||
|
class TCPPortScanner : PortScannerBase
|
||||||
|
{
|
||||||
|
// The TCP client for port scanning
|
||||||
|
private TcpClient tcpClient;
|
||||||
|
|
||||||
|
// Constructor - uses base class constructor
|
||||||
|
public TCPPortScanner() : base()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementing the base's abstract method CheckOpenAsync(), cancellation token ct passed from MainWindow, triggered in the cancel button click event
|
||||||
|
public override async Task<bool> CheckOpenAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
using (tcpClient = new TcpClient())
|
||||||
|
{
|
||||||
|
// connection is the Task returned by ConnectAsync
|
||||||
|
var connection = tcpClient.ConnectAsync(Hostname, Port);
|
||||||
|
|
||||||
|
bool returnValue;
|
||||||
|
|
||||||
|
// In case the ct is triggered, this will act as if delay expired right when the click occurrs
|
||||||
|
if (await Task.WhenAny(connection, Task.Delay(Timeout, ct)) == connection)
|
||||||
|
{
|
||||||
|
// If connection was refused, return false
|
||||||
|
// The exception within the task is a SocketException if the connection failed
|
||||||
|
if (connection.Exception != null)
|
||||||
|
{
|
||||||
|
returnValue = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
returnValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Timeout occurred, this means that there is no connection and port is closed
|
||||||
|
returnValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpClient.Close();
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Networking/PortScanner/TimeoutListItem.cs
Normal file
44
Networking/PortScanner/TimeoutListItem.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
// This class represents one item in the list of items that will be
|
||||||
|
// displayed in the timeout time combo box in the MainWindow
|
||||||
|
|
||||||
|
namespace PortScanner
|
||||||
|
{
|
||||||
|
class TimeoutListItem
|
||||||
|
{
|
||||||
|
// DisplayMember: the string that will be displayed in the timeout combo box
|
||||||
|
// ValueMember: the actual ms value attached to that string
|
||||||
|
public string DisplayMember { get; set; }
|
||||||
|
public int ValueMember { get; set; }
|
||||||
|
|
||||||
|
// The array of different values present in the combo box
|
||||||
|
// Add new values right here ......
|
||||||
|
private static int[] _times =
|
||||||
|
{
|
||||||
|
500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns a list of objects of this class intended to be used
|
||||||
|
// as a datasource for a combo box
|
||||||
|
public static List<TimeoutListItem> CreateTimeoutListItems()
|
||||||
|
{
|
||||||
|
var returnList = new List<TimeoutListItem>();
|
||||||
|
|
||||||
|
for (int i = 0; i < _times.Length; i++)
|
||||||
|
{
|
||||||
|
returnList.Add(new TimeoutListItem
|
||||||
|
{
|
||||||
|
DisplayMember = String.Format("{0} ms", _times[i]),
|
||||||
|
ValueMember = _times[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
94
Networking/PortScanner/UDPPortScanner.cs
Normal file
94
Networking/PortScanner/UDPPortScanner.cs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
using Networking.Pages;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace PortScanner
|
||||||
|
{
|
||||||
|
class UDPPortScanner : PortScannerBase
|
||||||
|
{
|
||||||
|
// The UDP client used for scanning a port
|
||||||
|
private UdpClient udpClient;
|
||||||
|
|
||||||
|
// Constructor - use base constructor
|
||||||
|
public UDPPortScanner() : base()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
public async override Task<bool> CheckOpenAsync(CancellationToken ct)
|
||||||
|
{
|
||||||
|
// We are using a UDP client to see whether the port is open or not
|
||||||
|
// Therefore, the absence of a response means that the port is open
|
||||||
|
// If there is any respone, it is closed
|
||||||
|
using (udpClient = new UdpClient())
|
||||||
|
{
|
||||||
|
bool returnVal;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Connect to the server
|
||||||
|
udpClient.Connect(Hostname, Port);
|
||||||
|
|
||||||
|
// Set the timeout
|
||||||
|
udpClient.Client.ReceiveTimeout = Timeout;
|
||||||
|
|
||||||
|
// Sends a message over UDP
|
||||||
|
Byte[] sendBytes = Encoding.ASCII.GetBytes("Are you open?");
|
||||||
|
udpClient.Send(sendBytes, sendBytes.Length);
|
||||||
|
|
||||||
|
// IPEndPoint object will allow us to read datagrams sent from any source.
|
||||||
|
// Port 0 means any available port
|
||||||
|
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||||
|
|
||||||
|
// Asynchronously begin receiving
|
||||||
|
var result = udpClient.ReceiveAsync();
|
||||||
|
if (await Task.WhenAny(result, Task.Delay(Timeout, ct)) == result)
|
||||||
|
{
|
||||||
|
Console.WriteLine(Encoding.ASCII.GetString(result.Result.Buffer));
|
||||||
|
returnVal = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// There was no response, we will consider this port as open
|
||||||
|
returnVal = true;
|
||||||
|
}
|
||||||
|
udpClient.Close();
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
catch (SocketException e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Error Code: " + e.ErrorCode);
|
||||||
|
|
||||||
|
switch (e.ErrorCode)
|
||||||
|
{
|
||||||
|
case 10054:
|
||||||
|
returnVal = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11001:
|
||||||
|
returnVal = false;
|
||||||
|
|
||||||
|
// Display an error message on the main thread
|
||||||
|
MessageBox.Show(
|
||||||
|
"Hostname could not be resolved.",
|
||||||
|
"Connection Error",
|
||||||
|
MessageBoxButtons.OK,
|
||||||
|
MessageBoxIcon.Error);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
returnVal = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
udpClient.Close();
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
138
Networking/SmartThreadPool/CallerThreadContext.cs
Normal file
138
Networking/SmartThreadPool/CallerThreadContext.cs
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Web;
|
||||||
|
using System.Runtime.Remoting.Messaging;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
#region CallerThreadContext class
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class stores the caller call context in order to restore
|
||||||
|
/// it when the work item is executed in the thread pool environment.
|
||||||
|
/// </summary>
|
||||||
|
internal class CallerThreadContext
|
||||||
|
{
|
||||||
|
#region Prepare reflection information
|
||||||
|
|
||||||
|
// Cached type information.
|
||||||
|
private static readonly MethodInfo getLogicalCallContextMethodInfo =
|
||||||
|
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
private static readonly MethodInfo setLogicalCallContextMethodInfo =
|
||||||
|
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
private static string HttpContextSlotName = GetHttpContextSlotName();
|
||||||
|
|
||||||
|
private static string GetHttpContextSlotName()
|
||||||
|
{
|
||||||
|
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
if (fi != null)
|
||||||
|
{
|
||||||
|
return (string) fi.GetValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "HttpContext";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private fields
|
||||||
|
|
||||||
|
private HttpContext _httpContext;
|
||||||
|
private LogicalCallContext _callContext;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
private CallerThreadContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CapturedCallContext
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (null != _callContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CapturedHttpContext
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (null != _httpContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Captures the current thread context
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static CallerThreadContext Capture(
|
||||||
|
bool captureCallContext,
|
||||||
|
bool captureHttpContext)
|
||||||
|
{
|
||||||
|
Debug.Assert(captureCallContext || captureHttpContext);
|
||||||
|
|
||||||
|
CallerThreadContext callerThreadContext = new CallerThreadContext();
|
||||||
|
|
||||||
|
// TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
|
||||||
|
// Capture Call Context
|
||||||
|
if(captureCallContext && (getLogicalCallContextMethodInfo != null))
|
||||||
|
{
|
||||||
|
callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
|
||||||
|
if (callerThreadContext._callContext != null)
|
||||||
|
{
|
||||||
|
callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture httpContext
|
||||||
|
if (captureHttpContext && (null != HttpContext.Current))
|
||||||
|
{
|
||||||
|
callerThreadContext._httpContext = HttpContext.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
return callerThreadContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the thread context stored earlier
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callerThreadContext"></param>
|
||||||
|
public static void Apply(CallerThreadContext callerThreadContext)
|
||||||
|
{
|
||||||
|
if (null == callerThreadContext)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("callerThreadContext");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
|
||||||
|
// Restore call context
|
||||||
|
if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
|
||||||
|
{
|
||||||
|
setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore HttpContext
|
||||||
|
if (callerThreadContext._httpContext != null)
|
||||||
|
{
|
||||||
|
HttpContext.Current = callerThreadContext._httpContext;
|
||||||
|
//CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endif
|
||||||
14
Networking/SmartThreadPool/CanceledWorkItemsGroup.cs
Normal file
14
Networking/SmartThreadPool/CanceledWorkItemsGroup.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
internal class CanceledWorkItemsGroup
|
||||||
|
{
|
||||||
|
public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||||
|
|
||||||
|
public CanceledWorkItemsGroup()
|
||||||
|
{
|
||||||
|
IsCanceled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCanceled { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
104
Networking/SmartThreadPool/EventWaitHandle.cs
Normal file
104
Networking/SmartThreadPool/EventWaitHandle.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#if (_WINDOWS_CE)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventWaitHandle class
|
||||||
|
/// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation.
|
||||||
|
/// So I wrote this class to implement these two methods with some of their overloads.
|
||||||
|
/// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny.
|
||||||
|
/// Note that this class doesn't even inherit from WaitHandle!
|
||||||
|
/// </summary>
|
||||||
|
public class STPEventWaitHandle
|
||||||
|
{
|
||||||
|
#region Public Constants
|
||||||
|
|
||||||
|
public const int WaitTimeout = Timeout.Infinite;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private External Constants
|
||||||
|
|
||||||
|
private const Int32 WAIT_FAILED = -1;
|
||||||
|
private const Int32 WAIT_TIMEOUT = 0x102;
|
||||||
|
private const UInt32 INFINITE = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region WaitAll and WaitAny
|
||||||
|
|
||||||
|
internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return waitHandle.WaitOne(millisecondsTimeout, exitContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles)
|
||||||
|
{
|
||||||
|
IntPtr[] nativeHandles = new IntPtr[waitHandles.Length];
|
||||||
|
for (int i = 0; i < waitHandles.Length; i++)
|
||||||
|
{
|
||||||
|
nativeHandles[i] = waitHandles[i].Handle;
|
||||||
|
}
|
||||||
|
return nativeHandles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
|
||||||
|
|
||||||
|
IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
|
||||||
|
|
||||||
|
int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout);
|
||||||
|
|
||||||
|
if (result == WAIT_TIMEOUT || result == WAIT_FAILED)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
|
||||||
|
|
||||||
|
IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
|
||||||
|
|
||||||
|
int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout);
|
||||||
|
|
||||||
|
if (result >= 0 && result < waitHandles.Length)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int WaitAny(WaitHandle[] waitHandles)
|
||||||
|
{
|
||||||
|
return WaitAny(waitHandles, Timeout.Infinite, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
|
||||||
|
{
|
||||||
|
int millisecondsTimeout = (int)timeout.TotalMilliseconds;
|
||||||
|
|
||||||
|
return WaitAny(waitHandles, millisecondsTimeout, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region External methods
|
||||||
|
|
||||||
|
[DllImport("coredll.dll", SetLastError = true)]
|
||||||
|
public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
82
Networking/SmartThreadPool/EventWaitHandleFactory.cs
Normal file
82
Networking/SmartThreadPool/EventWaitHandleFactory.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
#if (_WINDOWS_CE)
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventWaitHandleFactory class.
|
||||||
|
/// This is a static class that creates AutoResetEvent and ManualResetEvent objects.
|
||||||
|
/// In WindowCE the WaitForMultipleObjects API fails to use the Handle property
|
||||||
|
/// of XxxResetEvent. It can use only handles that were created by the CreateEvent API.
|
||||||
|
/// Consequently this class creates the needed XxxResetEvent and replaces the handle if
|
||||||
|
/// it's a WindowsCE OS.
|
||||||
|
/// </summary>
|
||||||
|
public static class EventWaitHandleFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new AutoResetEvent object
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Return a new AutoResetEvent object</returns>
|
||||||
|
public static AutoResetEvent CreateAutoResetEvent()
|
||||||
|
{
|
||||||
|
AutoResetEvent waitHandle = new AutoResetEvent(false);
|
||||||
|
|
||||||
|
#if (_WINDOWS_CE)
|
||||||
|
ReplaceEventHandle(waitHandle, false, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return waitHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new ManualResetEvent object
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Return a new ManualResetEvent object</returns>
|
||||||
|
public static ManualResetEvent CreateManualResetEvent(bool initialState)
|
||||||
|
{
|
||||||
|
ManualResetEvent waitHandle = new ManualResetEvent(initialState);
|
||||||
|
|
||||||
|
#if (_WINDOWS_CE)
|
||||||
|
ReplaceEventHandle(waitHandle, true, initialState);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return waitHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (_WINDOWS_CE)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replace the event handle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="waitHandle">The WaitHandle object which its handle needs to be replaced.</param>
|
||||||
|
/// <param name="manualReset">Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)</param>
|
||||||
|
/// <param name="initialState">The initial state of the event</param>
|
||||||
|
private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState)
|
||||||
|
{
|
||||||
|
// Store the old handle
|
||||||
|
IntPtr oldHandle = waitHandle.Handle;
|
||||||
|
|
||||||
|
// Create a new event
|
||||||
|
IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null);
|
||||||
|
|
||||||
|
// Replace the old event with the new event
|
||||||
|
waitHandle.Handle = newHandle;
|
||||||
|
|
||||||
|
// Close the old event
|
||||||
|
CloseHandle (oldHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("coredll.dll", SetLastError = true)]
|
||||||
|
public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
|
||||||
|
|
||||||
|
//Handle
|
||||||
|
[DllImport("coredll.dll", SetLastError = true)]
|
||||||
|
public static extern bool CloseHandle(IntPtr hObject);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
144
Networking/SmartThreadPool/Exceptions.cs
Normal file
144
Networking/SmartThreadPool/Exceptions.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
#if !(_WINDOWS_CE)
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
#region Exceptions
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class WorkItemCancelException : Exception
|
||||||
|
{
|
||||||
|
public WorkItemCancelException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemCancelException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemCancelException(string message, Exception e)
|
||||||
|
: base(message, e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class WorkItemTimeoutException : Exception
|
||||||
|
{
|
||||||
|
public WorkItemTimeoutException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemTimeoutException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemTimeoutException(string message, Exception e)
|
||||||
|
: base(message, e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class WorkItemResultException : Exception
|
||||||
|
{
|
||||||
|
public WorkItemResultException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemResultException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemResultException(string message, Exception e)
|
||||||
|
: base(message, e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case the STP queue is full and work item cannot be queued.
|
||||||
|
/// Relevant when the STP has a queue size limit
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class QueueRejectedException : Exception
|
||||||
|
{
|
||||||
|
public QueueRejectedException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueueRejectedException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueueRejectedException(string message, Exception e)
|
||||||
|
: base(message, e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public sealed partial class WorkItemCancelException
|
||||||
|
{
|
||||||
|
public WorkItemCancelException(SerializationInfo si, StreamingContext sc)
|
||||||
|
: base(si, sc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public sealed partial class WorkItemTimeoutException
|
||||||
|
{
|
||||||
|
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc)
|
||||||
|
: base(si, sc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public sealed partial class WorkItemResultException
|
||||||
|
{
|
||||||
|
public WorkItemResultException(SerializationInfo si, StreamingContext sc)
|
||||||
|
: base(si, sc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public sealed partial class QueueRejectedException
|
||||||
|
{
|
||||||
|
public QueueRejectedException(SerializationInfo si, StreamingContext sc)
|
||||||
|
: base(si, sc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
603
Networking/SmartThreadPool/Interfaces.cs
Normal file
603
Networking/SmartThreadPool/Interfaces.cs
Normal file
@@ -0,0 +1,603 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
#region Delegates
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate that represents the method to run as the work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">A state object for the method to run</param>
|
||||||
|
public delegate object WorkItemCallback(object state);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call after the WorkItemCallback completed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wir">The work item result object</param>
|
||||||
|
public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call after the WorkItemCallback completed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wir">The work item result object</param>
|
||||||
|
public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call when a WorkItemsGroup becomes idle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
|
||||||
|
public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call after a thread is created, but before
|
||||||
|
/// it's first use.
|
||||||
|
/// </summary>
|
||||||
|
public delegate void ThreadInitializationHandler();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call when a thread is about to exit, after
|
||||||
|
/// it is no longer belong to the pool.
|
||||||
|
/// </summary>
|
||||||
|
public delegate void ThreadTerminationHandler();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region WorkItem Priority
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the availeable priorities of a work item.
|
||||||
|
/// The higher the priority a work item has, the sooner
|
||||||
|
/// it will be executed.
|
||||||
|
/// </summary>
|
||||||
|
public enum WorkItemPriority
|
||||||
|
{
|
||||||
|
Lowest,
|
||||||
|
BelowNormal,
|
||||||
|
Normal,
|
||||||
|
AboveNormal,
|
||||||
|
Highest,
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IWorkItemsGroup interface
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IWorkItemsGroup interface
|
||||||
|
/// Created by SmartThreadPool.CreateWorkItemsGroup()
|
||||||
|
/// </summary>
|
||||||
|
public interface IWorkItemsGroup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the name of the WorkItemsGroup
|
||||||
|
/// </summary>
|
||||||
|
string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
|
||||||
|
/// </summary>
|
||||||
|
int Concurrency { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the number of work items waiting in the queue.
|
||||||
|
/// </summary>
|
||||||
|
int WaitingCallbacks { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the number of currently executing work items
|
||||||
|
/// </summary>
|
||||||
|
int InUseThreads { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get an array with all the state objects of the currently running items.
|
||||||
|
/// The array represents a snap shot and impact performance.
|
||||||
|
/// </summary>
|
||||||
|
object[] GetStates();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the WorkItemsGroup start information
|
||||||
|
/// </summary>
|
||||||
|
WIGStartInfo WIGStartInfo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts to execute work items
|
||||||
|
/// </summary>
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel all the work items.
|
||||||
|
/// Same as Cancel(false)
|
||||||
|
/// </summary>
|
||||||
|
void Cancel();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel all work items using thread abortion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
|
||||||
|
void Cancel(bool abortExecution);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for all work item to complete.
|
||||||
|
/// </summary>
|
||||||
|
void WaitForIdle();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for all work item to complete, until timeout expired
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeout">How long to wait for the work items to complete</param>
|
||||||
|
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
|
||||||
|
bool WaitForIdle(TimeSpan timeout);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for all work item to complete, until timeout expired
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param>
|
||||||
|
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
|
||||||
|
bool WaitForIdle(int millisecondsTimeout);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IsIdle is true when there are no work items running or queued.
|
||||||
|
/// </summary>
|
||||||
|
bool IsIdle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event is fired when all work items are completed.
|
||||||
|
/// (When IsIdle changes to true)
|
||||||
|
/// This event only work on WorkItemsGroup. On SmartThreadPool
|
||||||
|
/// it throws the NotImplementedException.
|
||||||
|
/// </summary>
|
||||||
|
event WorkItemsGroupIdleHandler OnIdle;
|
||||||
|
|
||||||
|
#region QueueWorkItem
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="workItemPriority">The priority of the work item</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemInfo">Work item info</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemInfo">Work item information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region QueueWorkItem(Action<...>)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(Action action, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||||
|
IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||||
|
IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||||
|
IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||||
|
IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region QueueWorkItem(Func<...>)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||||
|
/// its GetResult() returns a TResult object</returns>
|
||||||
|
IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||||
|
/// its GetResult() returns a TResult object</returns>
|
||||||
|
IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||||
|
/// its GetResult() returns a TResult object</returns>
|
||||||
|
IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||||
|
/// its GetResult() returns a TResult object</returns>
|
||||||
|
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult<TResult> object.
|
||||||
|
/// its GetResult() returns a TResult object</returns>
|
||||||
|
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region CallToPostExecute enumerator
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum CallToPostExecute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Never call to the PostExecute call back
|
||||||
|
/// </summary>
|
||||||
|
Never = 0x00,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Call to the PostExecute only when the work item is cancelled
|
||||||
|
/// </summary>
|
||||||
|
WhenWorkItemCanceled = 0x01,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Call to the PostExecute only when the work item is not cancelled
|
||||||
|
/// </summary>
|
||||||
|
WhenWorkItemNotCanceled = 0x02,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Always call to the PostExecute
|
||||||
|
/// </summary>
|
||||||
|
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IWorkItemResult interface
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The common interface of IWorkItemResult and IWorkItemResult<T>
|
||||||
|
/// </summary>
|
||||||
|
public interface IWaitableResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This method intent is for internal use.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
IWorkItemResult GetWorkItemResult();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method intent is for internal use.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
IWorkItemResult<TResult> GetWorkItemResultT<TResult>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IWorkItemResult interface.
|
||||||
|
/// Created when a WorkItemCallback work item is queued.
|
||||||
|
/// </summary>
|
||||||
|
public interface IWorkItemResult : IWorkItemResult<object>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IWorkItemResult<TResult> interface.
|
||||||
|
/// Created when a Func<TResult> work item is queued.
|
||||||
|
/// </summary>
|
||||||
|
public interface IWorkItemResult<TResult> : IWaitableResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
TResult GetResult();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
TResult GetResult(
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
TResult GetResult(
|
||||||
|
TimeSpan timeout,
|
||||||
|
bool exitContext);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
|
||||||
|
/// <param name="exitContext">
|
||||||
|
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
/// On cancel throws WorkItemCancelException
|
||||||
|
TResult GetResult(
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
/// On cancel throws WorkItemCancelException
|
||||||
|
TResult GetResult(
|
||||||
|
TimeSpan timeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
TResult GetResult(out Exception e);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="millisecondsTimeout"></param>
|
||||||
|
/// <param name="exitContext"></param>
|
||||||
|
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
TResult GetResult(
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext,
|
||||||
|
out Exception e);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exitContext"></param>
|
||||||
|
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||||
|
/// <param name="timeout"></param>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
TResult GetResult(
|
||||||
|
TimeSpan timeout,
|
||||||
|
bool exitContext,
|
||||||
|
out Exception e);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
|
||||||
|
/// <param name="exitContext">
|
||||||
|
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
|
||||||
|
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
/// On cancel throws WorkItemCancelException
|
||||||
|
TResult GetResult(
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle,
|
||||||
|
out Exception e);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
/// <param name="cancelWaitHandle"></param>
|
||||||
|
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||||
|
/// <param name="timeout"></param>
|
||||||
|
/// <param name="exitContext"></param>
|
||||||
|
/// On timeout throws WorkItemTimeoutException
|
||||||
|
/// On cancel throws WorkItemCancelException
|
||||||
|
TResult GetResult(
|
||||||
|
TimeSpan timeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle,
|
||||||
|
out Exception e);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an indication whether the asynchronous operation has completed.
|
||||||
|
/// </summary>
|
||||||
|
bool IsCompleted { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an indication whether the asynchronous operation has been canceled.
|
||||||
|
/// </summary>
|
||||||
|
bool IsCanceled { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the user-defined object that contains context data
|
||||||
|
/// for the work item method.
|
||||||
|
/// </summary>
|
||||||
|
object State { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Same as Cancel(false).
|
||||||
|
/// </summary>
|
||||||
|
bool Cancel();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel the work item execution.
|
||||||
|
/// If the work item is in the queue then it won't execute
|
||||||
|
/// If the work item is completed, it will remain completed
|
||||||
|
/// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled
|
||||||
|
/// property to check if the work item has been cancelled. If the abortExecution is set to true then
|
||||||
|
/// the Smart Thread Pool will send an AbortException to the running thread to stop the execution
|
||||||
|
/// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException.
|
||||||
|
/// If the work item is already cancelled it will remain cancelled
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="abortExecution">When true send an AbortException to the executing thread.</param>
|
||||||
|
/// <returns>Returns true if the work item was not completed, otherwise false.</returns>
|
||||||
|
bool Cancel(bool abortExecution);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the work item's priority
|
||||||
|
/// </summary>
|
||||||
|
WorkItemPriority WorkItemPriority { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return the result, same as GetResult()
|
||||||
|
/// </summary>
|
||||||
|
TResult Result { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the exception if occured otherwise returns null.
|
||||||
|
/// </summary>
|
||||||
|
object Exception { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region .NET 3.5
|
||||||
|
|
||||||
|
// All these delegate are built-in .NET 3.5
|
||||||
|
// Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity.
|
||||||
|
|
||||||
|
public delegate void Action();
|
||||||
|
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
|
||||||
|
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
|
||||||
|
public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
|
||||||
|
|
||||||
|
public delegate TResult Func<TResult>();
|
||||||
|
public delegate TResult Func<T, TResult>(T arg1);
|
||||||
|
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
|
||||||
|
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
|
||||||
|
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
27
Networking/SmartThreadPool/InternalInterfaces.cs
Normal file
27
Networking/SmartThreadPool/InternalInterfaces.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An internal delegate to call when the WorkItem starts or completes
|
||||||
|
/// </summary>
|
||||||
|
internal delegate void WorkItemStateCallback(WorkItem workItem);
|
||||||
|
|
||||||
|
internal interface IInternalWorkItemResult
|
||||||
|
{
|
||||||
|
event WorkItemStateCallback OnWorkItemStarted;
|
||||||
|
event WorkItemStateCallback OnWorkItemCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface IInternalWaitableResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This method is intent for internal use.
|
||||||
|
/// </summary>
|
||||||
|
IWorkItemResult GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasWorkItemPriority
|
||||||
|
{
|
||||||
|
WorkItemPriority WorkItemPriority { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
239
Networking/SmartThreadPool/PriorityQueue.cs
Normal file
239
Networking/SmartThreadPool/PriorityQueue.cs
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
#region PriorityQueue class
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// PriorityQueue class
|
||||||
|
/// This class is not thread safe because we use external lock
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PriorityQueue : IEnumerable
|
||||||
|
{
|
||||||
|
#region Private members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of queues, there is one for each type of priority
|
||||||
|
/// </summary>
|
||||||
|
private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Work items queues. There is one for each type of priority
|
||||||
|
/// </summary>
|
||||||
|
private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total number of work items within the queues
|
||||||
|
/// </summary>
|
||||||
|
private int _workItemsCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Use with IEnumerable interface
|
||||||
|
/// </summary>
|
||||||
|
private int _version;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Contructor
|
||||||
|
|
||||||
|
public PriorityQueue()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < _queues.Length; ++i)
|
||||||
|
{
|
||||||
|
_queues[i] = new LinkedList<IHasWorkItemPriority>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enqueue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItem">A work item</param>
|
||||||
|
public void Enqueue(IHasWorkItemPriority workItem)
|
||||||
|
{
|
||||||
|
Debug.Assert(null != workItem);
|
||||||
|
|
||||||
|
int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
|
||||||
|
Debug.Assert(queueIndex >= 0);
|
||||||
|
Debug.Assert(queueIndex < _queuesCount);
|
||||||
|
|
||||||
|
_queues[queueIndex].AddLast(workItem);
|
||||||
|
++_workItemsCount;
|
||||||
|
++_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dequeque a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns the next work item</returns>
|
||||||
|
public IHasWorkItemPriority Dequeue()
|
||||||
|
{
|
||||||
|
IHasWorkItemPriority workItem = null;
|
||||||
|
|
||||||
|
if(_workItemsCount > 0)
|
||||||
|
{
|
||||||
|
int queueIndex = GetNextNonEmptyQueue(-1);
|
||||||
|
Debug.Assert(queueIndex >= 0);
|
||||||
|
workItem = _queues[queueIndex].First.Value;
|
||||||
|
_queues[queueIndex].RemoveFirst();
|
||||||
|
Debug.Assert(null != workItem);
|
||||||
|
--_workItemsCount;
|
||||||
|
++_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find the next non empty queue starting at queue queueIndex+1
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="queueIndex">The index-1 to start from</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The index of the next non empty queue or -1 if all the queues are empty
|
||||||
|
/// </returns>
|
||||||
|
private int GetNextNonEmptyQueue(int queueIndex)
|
||||||
|
{
|
||||||
|
for(int i = queueIndex+1; i < _queuesCount; ++i)
|
||||||
|
{
|
||||||
|
if(_queues[i].Count > 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of work items
|
||||||
|
/// </summary>
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItemsCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear all the work items
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
if (_workItemsCount > 0)
|
||||||
|
{
|
||||||
|
foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
|
||||||
|
{
|
||||||
|
queue.Clear();
|
||||||
|
}
|
||||||
|
_workItemsCount = 0;
|
||||||
|
++_version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEnumerable Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator to iterate over the work items
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns an enumerator</returns>
|
||||||
|
public IEnumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new PriorityQueueEnumerator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region PriorityQueueEnumerator
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The class the implements the enumerator
|
||||||
|
/// </summary>
|
||||||
|
private class PriorityQueueEnumerator : IEnumerator
|
||||||
|
{
|
||||||
|
private readonly PriorityQueue _priorityQueue;
|
||||||
|
private int _version;
|
||||||
|
private int _queueIndex;
|
||||||
|
private IEnumerator _enumerator;
|
||||||
|
|
||||||
|
public PriorityQueueEnumerator(PriorityQueue priorityQueue)
|
||||||
|
{
|
||||||
|
_priorityQueue = priorityQueue;
|
||||||
|
_version = _priorityQueue._version;
|
||||||
|
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
|
||||||
|
if (_queueIndex >= 0)
|
||||||
|
{
|
||||||
|
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_enumerator = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IEnumerator Members
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_version = _priorityQueue._version;
|
||||||
|
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
|
||||||
|
if (_queueIndex >= 0)
|
||||||
|
{
|
||||||
|
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_enumerator = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Debug.Assert(null != _enumerator);
|
||||||
|
return _enumerator.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (null == _enumerator)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_version != _priorityQueue._version)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("The collection has been modified");
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!_enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
|
||||||
|
if(-1 == _queueIndex)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
|
||||||
|
_enumerator.MoveNext();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
16
Networking/SmartThreadPool/SLExt.cs
Normal file
16
Networking/SmartThreadPool/SLExt.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#if _SILVERLIGHT
|
||||||
|
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
public enum ThreadPriority
|
||||||
|
{
|
||||||
|
Lowest,
|
||||||
|
BelowNormal,
|
||||||
|
Normal,
|
||||||
|
AboveNormal,
|
||||||
|
Highest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
62
Networking/SmartThreadPool/STPEventWaitHandle.cs
Normal file
62
Networking/SmartThreadPool/STPEventWaitHandle.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#if !(_WINDOWS_CE)
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
#if _SILVERLIGHT || WINDOWS_PHONE
|
||||||
|
internal static class STPEventWaitHandle
|
||||||
|
{
|
||||||
|
public const int WaitTimeout = Timeout.Infinite;
|
||||||
|
|
||||||
|
internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return WaitHandle.WaitAll(waitHandles, millisecondsTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int WaitAny(WaitHandle[] waitHandles)
|
||||||
|
{
|
||||||
|
return WaitHandle.WaitAny(waitHandles);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return WaitHandle.WaitAny(waitHandles, millisecondsTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return waitHandle.WaitOne(millisecondsTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
internal static class STPEventWaitHandle
|
||||||
|
{
|
||||||
|
public const int WaitTimeout = Timeout.Infinite;
|
||||||
|
|
||||||
|
internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int WaitAny(WaitHandle[] waitHandles)
|
||||||
|
{
|
||||||
|
return WaitHandle.WaitAny(waitHandles);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return waitHandle.WaitOne(millisecondsTimeout, exitContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
448
Networking/SmartThreadPool/STPPerformanceCounter.cs
Normal file
448
Networking/SmartThreadPool/STPPerformanceCounter.cs
Normal file
@@ -0,0 +1,448 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
public interface ISTPPerformanceCountersReader
|
||||||
|
{
|
||||||
|
long InUseThreads { get; }
|
||||||
|
long ActiveThreads { get; }
|
||||||
|
long WorkItemsQueued { get; }
|
||||||
|
long WorkItemsProcessed { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
internal interface ISTPInstancePerformanceCounters : IDisposable
|
||||||
|
{
|
||||||
|
void Close();
|
||||||
|
void SampleThreads(long activeThreads, long inUseThreads);
|
||||||
|
void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
|
||||||
|
void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
|
||||||
|
void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
|
||||||
|
}
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
|
||||||
|
internal enum STPPerformanceCounterType
|
||||||
|
{
|
||||||
|
// Fields
|
||||||
|
ActiveThreads = 0,
|
||||||
|
InUseThreads = 1,
|
||||||
|
OverheadThreads = 2,
|
||||||
|
OverheadThreadsPercent = 3,
|
||||||
|
OverheadThreadsPercentBase = 4,
|
||||||
|
|
||||||
|
WorkItems = 5,
|
||||||
|
WorkItemsInQueue = 6,
|
||||||
|
WorkItemsProcessed = 7,
|
||||||
|
|
||||||
|
WorkItemsQueuedPerSecond = 8,
|
||||||
|
WorkItemsProcessedPerSecond = 9,
|
||||||
|
|
||||||
|
AvgWorkItemWaitTime = 10,
|
||||||
|
AvgWorkItemWaitTimeBase = 11,
|
||||||
|
|
||||||
|
AvgWorkItemProcessTime = 12,
|
||||||
|
AvgWorkItemProcessTimeBase = 13,
|
||||||
|
|
||||||
|
WorkItemsGroups = 14,
|
||||||
|
|
||||||
|
LastCounter = 14,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Summary description for STPPerformanceCounter.
|
||||||
|
/// </summary>
|
||||||
|
internal class STPPerformanceCounter
|
||||||
|
{
|
||||||
|
// Fields
|
||||||
|
private readonly PerformanceCounterType _pcType;
|
||||||
|
protected string _counterHelp;
|
||||||
|
protected string _counterName;
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
public STPPerformanceCounter(
|
||||||
|
string counterName,
|
||||||
|
string counterHelp,
|
||||||
|
PerformanceCounterType pcType)
|
||||||
|
{
|
||||||
|
_counterName = counterName;
|
||||||
|
_counterHelp = counterHelp;
|
||||||
|
_pcType = pcType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCounterToCollection(CounterCreationDataCollection counterData)
|
||||||
|
{
|
||||||
|
CounterCreationData counterCreationData = new CounterCreationData(
|
||||||
|
_counterName,
|
||||||
|
_counterHelp,
|
||||||
|
_pcType);
|
||||||
|
|
||||||
|
counterData.Add(counterCreationData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _counterName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class STPPerformanceCounters
|
||||||
|
{
|
||||||
|
// Fields
|
||||||
|
internal STPPerformanceCounter[] _stpPerformanceCounters;
|
||||||
|
private static readonly STPPerformanceCounters _instance;
|
||||||
|
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
|
||||||
|
internal const string _stpCategoryName = "SmartThreadPool";
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
static STPPerformanceCounters()
|
||||||
|
{
|
||||||
|
_instance = new STPPerformanceCounters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private STPPerformanceCounters()
|
||||||
|
{
|
||||||
|
STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[]
|
||||||
|
{
|
||||||
|
new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32),
|
||||||
|
new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32),
|
||||||
|
new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32),
|
||||||
|
new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction),
|
||||||
|
new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase),
|
||||||
|
|
||||||
|
new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32),
|
||||||
|
new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32),
|
||||||
|
new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32),
|
||||||
|
|
||||||
|
new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32),
|
||||||
|
new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32),
|
||||||
|
|
||||||
|
new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64),
|
||||||
|
new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase),
|
||||||
|
|
||||||
|
new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64),
|
||||||
|
new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase),
|
||||||
|
|
||||||
|
new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32),
|
||||||
|
};
|
||||||
|
|
||||||
|
_stpPerformanceCounters = stpPerformanceCounters;
|
||||||
|
SetupCategory();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupCategory()
|
||||||
|
{
|
||||||
|
if (!PerformanceCounterCategory.Exists(_stpCategoryName))
|
||||||
|
{
|
||||||
|
CounterCreationDataCollection counters = new CounterCreationDataCollection();
|
||||||
|
|
||||||
|
for (int i = 0; i < _stpPerformanceCounters.Length; i++)
|
||||||
|
{
|
||||||
|
_stpPerformanceCounters[i].AddCounterToCollection(counters);
|
||||||
|
}
|
||||||
|
|
||||||
|
PerformanceCounterCategory.Create(
|
||||||
|
_stpCategoryName,
|
||||||
|
_stpCategoryHelp,
|
||||||
|
PerformanceCounterCategoryType.MultiInstance,
|
||||||
|
counters);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
public static STPPerformanceCounters Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class STPInstancePerformanceCounter : IDisposable
|
||||||
|
{
|
||||||
|
// Fields
|
||||||
|
private bool _isDisposed;
|
||||||
|
private PerformanceCounter _pcs;
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
protected STPInstancePerformanceCounter()
|
||||||
|
{
|
||||||
|
_isDisposed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public STPInstancePerformanceCounter(
|
||||||
|
string instance,
|
||||||
|
STPPerformanceCounterType spcType) : this()
|
||||||
|
{
|
||||||
|
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
|
||||||
|
_pcs = new PerformanceCounter(
|
||||||
|
STPPerformanceCounters._stpCategoryName,
|
||||||
|
counters._stpPerformanceCounters[(int) spcType].Name,
|
||||||
|
instance,
|
||||||
|
false);
|
||||||
|
_pcs.RawValue = _pcs.RawValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
if (_pcs != null)
|
||||||
|
{
|
||||||
|
_pcs.RemoveInstance();
|
||||||
|
_pcs.Close();
|
||||||
|
_pcs = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isDisposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Increment()
|
||||||
|
{
|
||||||
|
_pcs.Increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void IncrementBy(long val)
|
||||||
|
{
|
||||||
|
_pcs.IncrementBy(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Set(long val)
|
||||||
|
{
|
||||||
|
_pcs.RawValue = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
|
||||||
|
{
|
||||||
|
// Methods
|
||||||
|
public override void Increment() {}
|
||||||
|
public override void IncrementBy(long value) {}
|
||||||
|
public override void Set(long val) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters
|
||||||
|
{
|
||||||
|
private bool _isDisposed;
|
||||||
|
// Fields
|
||||||
|
private STPInstancePerformanceCounter[] _pcs;
|
||||||
|
private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
static STPInstancePerformanceCounters()
|
||||||
|
{
|
||||||
|
_stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
public STPInstancePerformanceCounters(string instance)
|
||||||
|
{
|
||||||
|
_isDisposed = false;
|
||||||
|
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
|
||||||
|
|
||||||
|
// Call the STPPerformanceCounters.Instance so the static constructor will
|
||||||
|
// intialize the STPPerformanceCounters singleton.
|
||||||
|
STPPerformanceCounters.Instance.GetHashCode();
|
||||||
|
|
||||||
|
for (int i = 0; i < _pcs.Length; i++)
|
||||||
|
{
|
||||||
|
if (instance != null)
|
||||||
|
{
|
||||||
|
_pcs[i] = new STPInstancePerformanceCounter(
|
||||||
|
instance,
|
||||||
|
(STPPerformanceCounterType) i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pcs[i] = _stpInstanceNullPerformanceCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
if (null != _pcs)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _pcs.Length; i++)
|
||||||
|
{
|
||||||
|
if (null != _pcs[i])
|
||||||
|
{
|
||||||
|
_pcs[i].Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_pcs = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isDisposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
|
||||||
|
{
|
||||||
|
return _pcs[(int) spcType];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleThreads(long activeThreads, long inUseThreads)
|
||||||
|
{
|
||||||
|
GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads);
|
||||||
|
GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads);
|
||||||
|
GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
|
||||||
|
|
||||||
|
GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
|
||||||
|
GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
|
||||||
|
{
|
||||||
|
GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed);
|
||||||
|
GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued);
|
||||||
|
GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
|
||||||
|
|
||||||
|
GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
|
||||||
|
GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
|
||||||
|
{
|
||||||
|
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds);
|
||||||
|
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
|
||||||
|
{
|
||||||
|
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds);
|
||||||
|
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
|
||||||
|
{
|
||||||
|
private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters();
|
||||||
|
|
||||||
|
public static NullSTPInstancePerformanceCounters Instance
|
||||||
|
{
|
||||||
|
get { return _instance; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close() {}
|
||||||
|
public void Dispose() {}
|
||||||
|
|
||||||
|
public void SampleThreads(long activeThreads, long inUseThreads) {}
|
||||||
|
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
|
||||||
|
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
|
||||||
|
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
|
||||||
|
public long InUseThreads
|
||||||
|
{
|
||||||
|
get { return 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ActiveThreads
|
||||||
|
{
|
||||||
|
get { return 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long WorkItemsQueued
|
||||||
|
{
|
||||||
|
get { return 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long WorkItemsProcessed
|
||||||
|
{
|
||||||
|
get { return 0; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
|
||||||
|
{
|
||||||
|
public void Close() { }
|
||||||
|
public void Dispose() { }
|
||||||
|
|
||||||
|
private long _activeThreads;
|
||||||
|
private long _inUseThreads;
|
||||||
|
private long _workItemsQueued;
|
||||||
|
private long _workItemsProcessed;
|
||||||
|
|
||||||
|
public long InUseThreads
|
||||||
|
{
|
||||||
|
get { return _inUseThreads; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ActiveThreads
|
||||||
|
{
|
||||||
|
get { return _activeThreads; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long WorkItemsQueued
|
||||||
|
{
|
||||||
|
get { return _workItemsQueued; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long WorkItemsProcessed
|
||||||
|
{
|
||||||
|
get { return _workItemsProcessed; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleThreads(long activeThreads, long inUseThreads)
|
||||||
|
{
|
||||||
|
_activeThreads = activeThreads;
|
||||||
|
_inUseThreads = inUseThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
|
||||||
|
{
|
||||||
|
_workItemsQueued = workItemsQueued;
|
||||||
|
_workItemsProcessed = workItemsProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
|
||||||
|
{
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
|
||||||
|
{
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
235
Networking/SmartThreadPool/STPStartInfo.cs
Normal file
235
Networking/SmartThreadPool/STPStartInfo.cs
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Summary description for STPStartInfo.
|
||||||
|
/// </summary>
|
||||||
|
public class STPStartInfo : WIGStartInfo
|
||||||
|
{
|
||||||
|
private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||||
|
private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
||||||
|
private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||||
|
#if !(WINDOWS_PHONE)
|
||||||
|
private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||||
|
#endif
|
||||||
|
private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||||
|
private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground;
|
||||||
|
private bool _enableLocalPerformanceCounters;
|
||||||
|
private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
|
||||||
|
private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize;
|
||||||
|
private int? _maxQueueLength = SmartThreadPool.DefaultMaxQueueLength;
|
||||||
|
|
||||||
|
public STPStartInfo()
|
||||||
|
{
|
||||||
|
_performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||||
|
#if !(WINDOWS_PHONE)
|
||||||
|
_threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||||
|
#endif
|
||||||
|
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||||
|
_idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||||
|
_minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public STPStartInfo(STPStartInfo stpStartInfo)
|
||||||
|
: base(stpStartInfo)
|
||||||
|
{
|
||||||
|
_idleTimeout = stpStartInfo.IdleTimeout;
|
||||||
|
_minWorkerThreads = stpStartInfo.MinWorkerThreads;
|
||||||
|
_maxWorkerThreads = stpStartInfo.MaxWorkerThreads;
|
||||||
|
#if !(WINDOWS_PHONE)
|
||||||
|
_threadPriority = stpStartInfo.ThreadPriority;
|
||||||
|
#endif
|
||||||
|
_performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName;
|
||||||
|
_enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters;
|
||||||
|
_threadPoolName = stpStartInfo._threadPoolName;
|
||||||
|
_areThreadsBackground = stpStartInfo.AreThreadsBackground;
|
||||||
|
_maxQueueLength = stpStartInfo.MaxQueueLength;
|
||||||
|
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
_apartmentState = stpStartInfo._apartmentState;
|
||||||
|
#endif
|
||||||
|
_maxStackSize = stpStartInfo._maxStackSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the idle timeout in milliseconds.
|
||||||
|
/// If a thread is idle (starved) longer than IdleTimeout then it may quit.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int IdleTimeout
|
||||||
|
{
|
||||||
|
get { return _idleTimeout; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_idleTimeout = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the lower limit of threads in the pool.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int MinWorkerThreads
|
||||||
|
{
|
||||||
|
get { return _minWorkerThreads; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_minWorkerThreads = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the upper limit of threads in the pool.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int MaxWorkerThreads
|
||||||
|
{
|
||||||
|
get { return _maxWorkerThreads; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_maxWorkerThreads = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(WINDOWS_PHONE)
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the scheduling priority of the threads in the pool.
|
||||||
|
/// The Os handles the scheduling.
|
||||||
|
/// </summary>
|
||||||
|
public virtual ThreadPriority ThreadPriority
|
||||||
|
{
|
||||||
|
get { return _threadPriority; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_threadPriority = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the thread pool name. Threads will get names depending on this.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ThreadPoolName {
|
||||||
|
get { return _threadPoolName; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly ();
|
||||||
|
_threadPoolName = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the performance counter instance name of this SmartThreadPool
|
||||||
|
/// The default is null which indicate not to use performance counters at all.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string PerformanceCounterInstanceName
|
||||||
|
{
|
||||||
|
get { return _performanceCounterInstanceName; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_performanceCounterInstanceName = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable/Disable the local performance counter.
|
||||||
|
/// This enables the user to get some performance information about the SmartThreadPool
|
||||||
|
/// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.)
|
||||||
|
/// The default is false.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool EnableLocalPerformanceCounters
|
||||||
|
{
|
||||||
|
get { return _enableLocalPerformanceCounters; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_enableLocalPerformanceCounters = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set backgroundness of thread in thread pool.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool AreThreadsBackground
|
||||||
|
{
|
||||||
|
get { return _areThreadsBackground; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly ();
|
||||||
|
_areThreadsBackground = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of items allowed in the queue. Items attempting to be queued
|
||||||
|
/// when the queue is at its maximum will throw a QueueRejectedException.
|
||||||
|
///
|
||||||
|
/// Value must be > 0. A <code>null</code> value will leave the queue unbounded (i.e.
|
||||||
|
/// bounded only by available resources).
|
||||||
|
///
|
||||||
|
/// Ignored when <code>Enqueue()</code>ing on a Thread Pool from within a
|
||||||
|
/// <code>WorkItemsGroup</code>.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int? MaxQueueLength
|
||||||
|
{
|
||||||
|
get { return _maxQueueLength; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_maxQueueLength = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a readonly version of this STPStartInfo.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a readonly reference to this STPStartInfo</returns>
|
||||||
|
public new STPStartInfo AsReadOnly()
|
||||||
|
{
|
||||||
|
return new STPStartInfo(this) { _readOnly = true };
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
|
||||||
|
private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the apartment state of threads in the thread pool
|
||||||
|
/// </summary>
|
||||||
|
public ApartmentState ApartmentState
|
||||||
|
{
|
||||||
|
get { return _apartmentState; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_apartmentState = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the max stack size of threads in the thread pool
|
||||||
|
/// </summary>
|
||||||
|
public int? MaxStackSize
|
||||||
|
{
|
||||||
|
get { return _maxStackSize; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
if (value.HasValue && value.Value < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("value", "Value must be greater than 0.");
|
||||||
|
}
|
||||||
|
_maxStackSize = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
60
Networking/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
Normal file
60
Networking/SmartThreadPool/SmartThreadPool.ThreadEntry.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using Amib.Threading.Internal;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
public partial class SmartThreadPool
|
||||||
|
{
|
||||||
|
#region ThreadEntry class
|
||||||
|
|
||||||
|
internal class ThreadEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The thread creation time
|
||||||
|
/// The value is stored as UTC value.
|
||||||
|
/// </summary>
|
||||||
|
private readonly DateTime _creationTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The last time this thread has been running
|
||||||
|
/// It is updated by IAmAlive() method
|
||||||
|
/// The value is stored as UTC value.
|
||||||
|
/// </summary>
|
||||||
|
private DateTime _lastAliveTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A reference from each thread in the thread pool to its SmartThreadPool
|
||||||
|
/// object container.
|
||||||
|
/// With this variable a thread can know whatever it belongs to a
|
||||||
|
/// SmartThreadPool.
|
||||||
|
/// </summary>
|
||||||
|
private readonly SmartThreadPool _associatedSmartThreadPool;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A reference to the current work item a thread from the thread pool
|
||||||
|
/// is executing.
|
||||||
|
/// </summary>
|
||||||
|
public WorkItem CurrentWorkItem { get; set; }
|
||||||
|
|
||||||
|
public ThreadEntry(SmartThreadPool stp)
|
||||||
|
{
|
||||||
|
_associatedSmartThreadPool = stp;
|
||||||
|
_creationTime = DateTime.UtcNow;
|
||||||
|
_lastAliveTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SmartThreadPool AssociatedSmartThreadPool
|
||||||
|
{
|
||||||
|
get { return _associatedSmartThreadPool; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IAmAlive()
|
||||||
|
{
|
||||||
|
_lastAliveTime = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
1811
Networking/SmartThreadPool/SmartThreadPool.cs
Normal file
1811
Networking/SmartThreadPool/SmartThreadPool.cs
Normal file
File diff suppressed because it is too large
Load Diff
108
Networking/SmartThreadPool/Stopwatch.cs
Normal file
108
Networking/SmartThreadPool/Stopwatch.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stopwatch class
|
||||||
|
/// Used with WindowsCE and Silverlight which don't have Stopwatch
|
||||||
|
/// </summary>
|
||||||
|
internal class Stopwatch
|
||||||
|
{
|
||||||
|
private long _elapsed;
|
||||||
|
private bool _isRunning;
|
||||||
|
private long _startTimeStamp;
|
||||||
|
|
||||||
|
public Stopwatch()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long GetElapsedDateTimeTicks()
|
||||||
|
{
|
||||||
|
long rawElapsedTicks = GetRawElapsedTicks();
|
||||||
|
return rawElapsedTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long GetRawElapsedTicks()
|
||||||
|
{
|
||||||
|
long elapsed = _elapsed;
|
||||||
|
if (_isRunning)
|
||||||
|
{
|
||||||
|
long ticks = GetTimestamp() - _startTimeStamp;
|
||||||
|
elapsed += ticks;
|
||||||
|
}
|
||||||
|
return elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long GetTimestamp()
|
||||||
|
{
|
||||||
|
return DateTime.UtcNow.Ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_elapsed = 0L;
|
||||||
|
_isRunning = false;
|
||||||
|
_startTimeStamp = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
if (!_isRunning)
|
||||||
|
{
|
||||||
|
_startTimeStamp = GetTimestamp();
|
||||||
|
_isRunning = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stopwatch StartNew()
|
||||||
|
{
|
||||||
|
Stopwatch stopwatch = new Stopwatch();
|
||||||
|
stopwatch.Start();
|
||||||
|
return stopwatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (_isRunning)
|
||||||
|
{
|
||||||
|
long ticks = GetTimestamp() - _startTimeStamp;
|
||||||
|
_elapsed += ticks;
|
||||||
|
_isRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
public TimeSpan Elapsed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new TimeSpan(GetElapsedDateTimeTicks());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ElapsedMilliseconds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (GetElapsedDateTimeTicks() / 0x2710L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ElapsedTicks
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetRawElapsedTicks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRunning
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _isRunning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
89
Networking/SmartThreadPool/SynchronizedDictionary.cs
Normal file
89
Networking/SmartThreadPool/SynchronizedDictionary.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
internal class SynchronizedDictionary<TKey, TValue>
|
||||||
|
{
|
||||||
|
private readonly Dictionary<TKey, TValue> _dictionary;
|
||||||
|
private readonly object _lock;
|
||||||
|
|
||||||
|
public SynchronizedDictionary()
|
||||||
|
{
|
||||||
|
_lock = new object();
|
||||||
|
_dictionary = new Dictionary<TKey, TValue>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get { return _dictionary.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(TKey key)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _dictionary.ContainsKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(TKey key)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_dictionary.Remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object SyncRoot
|
||||||
|
{
|
||||||
|
get { return _lock; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _dictionary[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_dictionary[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<TKey, TValue>.KeyCollection Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _dictionary.Keys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<TKey, TValue>.ValueCollection Values
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return _dictionary.Values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_dictionary.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
171
Networking/SmartThreadPool/WIGStartInfo.cs
Normal file
171
Networking/SmartThreadPool/WIGStartInfo.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Summary description for WIGStartInfo.
|
||||||
|
/// </summary>
|
||||||
|
public class WIGStartInfo
|
||||||
|
{
|
||||||
|
private bool _useCallerCallContext;
|
||||||
|
private bool _useCallerHttpContext;
|
||||||
|
private bool _disposeOfStateObjects;
|
||||||
|
private CallToPostExecute _callToPostExecute;
|
||||||
|
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
|
||||||
|
private bool _startSuspended;
|
||||||
|
private WorkItemPriority _workItemPriority;
|
||||||
|
private bool _fillStateWithArgs;
|
||||||
|
|
||||||
|
protected bool _readOnly;
|
||||||
|
|
||||||
|
public WIGStartInfo()
|
||||||
|
{
|
||||||
|
_fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
|
||||||
|
_workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||||
|
_startSuspended = SmartThreadPool.DefaultStartSuspended;
|
||||||
|
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||||
|
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||||
|
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||||
|
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||||
|
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WIGStartInfo(WIGStartInfo wigStartInfo)
|
||||||
|
{
|
||||||
|
_useCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
|
_useCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
|
_disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
_callToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
|
_postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||||
|
_workItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
_startSuspended = wigStartInfo.StartSuspended;
|
||||||
|
_fillStateWithArgs = wigStartInfo.FillStateWithArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ThrowIfReadOnly()
|
||||||
|
{
|
||||||
|
if (_readOnly)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("This is a readonly instance and set is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to use the caller's security context
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool UseCallerCallContext
|
||||||
|
{
|
||||||
|
get { return _useCallerCallContext; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_useCallerCallContext = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to use the caller's HTTP context
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool UseCallerHttpContext
|
||||||
|
{
|
||||||
|
get { return _useCallerHttpContext; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_useCallerHttpContext = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to dispose of the state object of a work item
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool DisposeOfStateObjects
|
||||||
|
{
|
||||||
|
get { return _disposeOfStateObjects; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_disposeOfStateObjects = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the run the post execute options
|
||||||
|
/// </summary>
|
||||||
|
public virtual CallToPostExecute CallToPostExecute
|
||||||
|
{
|
||||||
|
get { return _callToPostExecute; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_callToPostExecute = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the default post execute callback
|
||||||
|
/// </summary>
|
||||||
|
public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback
|
||||||
|
{
|
||||||
|
get { return _postExecuteWorkItemCallback; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_postExecuteWorkItemCallback = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if the work items execution should be suspended until the Start()
|
||||||
|
/// method is called.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool StartSuspended
|
||||||
|
{
|
||||||
|
get { return _startSuspended; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_startSuspended = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the default priority that a work item gets when it is enqueued
|
||||||
|
/// </summary>
|
||||||
|
public virtual WorkItemPriority WorkItemPriority
|
||||||
|
{
|
||||||
|
get { return _workItemPriority; }
|
||||||
|
set { _workItemPriority = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the
|
||||||
|
/// arguments as an object array into the state of the work item.
|
||||||
|
/// The arguments can be access later by IWorkItemResult.State.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool FillStateWithArgs
|
||||||
|
{
|
||||||
|
get { return _fillStateWithArgs; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_fillStateWithArgs = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a readonly version of this WIGStartInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a readonly reference to this WIGStartInfoRO</returns>
|
||||||
|
public WIGStartInfo AsReadOnly()
|
||||||
|
{
|
||||||
|
return new WIGStartInfo(this) { _readOnly = true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
190
Networking/SmartThreadPool/WorkItem.WorkItemResult.cs
Normal file
190
Networking/SmartThreadPool/WorkItem.WorkItemResult.cs
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
public partial class WorkItem
|
||||||
|
{
|
||||||
|
#region WorkItemResult class
|
||||||
|
|
||||||
|
private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A back reference to the work item
|
||||||
|
/// </summary>
|
||||||
|
private readonly WorkItem _workItem;
|
||||||
|
|
||||||
|
public WorkItemResult(WorkItem workItem)
|
||||||
|
{
|
||||||
|
_workItem = workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal WorkItem GetWorkItem()
|
||||||
|
{
|
||||||
|
return _workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IWorkItemResult Members
|
||||||
|
|
||||||
|
public bool IsCompleted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItem.IsCompleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCanceled
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItem.IsCanceled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult()
|
||||||
|
{
|
||||||
|
return _workItem.GetResult(Timeout.Infinite, true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult(millisecondsTimeout, exitContext, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(TimeSpan timeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(out Exception e)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult(Timeout.Infinite, true, null, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||||
|
{
|
||||||
|
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Cancel()
|
||||||
|
{
|
||||||
|
return Cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Cancel(bool abortExecution)
|
||||||
|
{
|
||||||
|
return _workItem.Cancel(abortExecution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object State
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItem._state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemPriority WorkItemPriority
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItem._workItemInfo.WorkItemPriority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return the result, same as GetResult()
|
||||||
|
/// </summary>
|
||||||
|
public object Result
|
||||||
|
{
|
||||||
|
get { return GetResult(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the exception if occured otherwise returns null.
|
||||||
|
/// This value is valid only after the work item completed,
|
||||||
|
/// before that it is always null.
|
||||||
|
/// </summary>
|
||||||
|
public object Exception
|
||||||
|
{
|
||||||
|
get { return _workItem._exception; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IInternalWorkItemResult Members
|
||||||
|
|
||||||
|
public event WorkItemStateCallback OnWorkItemStarted
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
_workItem.OnWorkItemStarted += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_workItem.OnWorkItemStarted -= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public event WorkItemStateCallback OnWorkItemCompleted
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
_workItem.OnWorkItemCompleted += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_workItem.OnWorkItemCompleted -= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IInternalWorkItemResult Members
|
||||||
|
|
||||||
|
public IWorkItemResult GetWorkItemResult()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult<TResult> GetWorkItemResultT<TResult>()
|
||||||
|
{
|
||||||
|
return new WorkItemResultTWrapper<TResult>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
994
Networking/SmartThreadPool/WorkItem.cs
Normal file
994
Networking/SmartThreadPool/WorkItem.cs
Normal file
@@ -0,0 +1,994 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
using Amib.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds a callback delegate and the state for that delegate.
|
||||||
|
/// </summary>
|
||||||
|
public partial class WorkItem : IHasWorkItemPriority
|
||||||
|
{
|
||||||
|
#region WorkItemState enum
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the state of the work item in the thread pool
|
||||||
|
/// </summary>
|
||||||
|
private enum WorkItemState
|
||||||
|
{
|
||||||
|
InQueue = 0, // Nexts: InProgress, Canceled
|
||||||
|
InProgress = 1, // Nexts: Completed, Canceled
|
||||||
|
Completed = 2, // Stays Completed
|
||||||
|
Canceled = 3, // Stays Canceled
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState)
|
||||||
|
{
|
||||||
|
bool valid = false;
|
||||||
|
|
||||||
|
switch (currentState)
|
||||||
|
{
|
||||||
|
case WorkItemState.InQueue:
|
||||||
|
valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState);
|
||||||
|
break;
|
||||||
|
case WorkItemState.InProgress:
|
||||||
|
valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState);
|
||||||
|
break;
|
||||||
|
case WorkItemState.Completed:
|
||||||
|
case WorkItemState.Canceled:
|
||||||
|
// Cannot be changed
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Unknown state
|
||||||
|
Debug.Assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback delegate for the callback.
|
||||||
|
/// </summary>
|
||||||
|
private readonly WorkItemCallback _callback;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// State with which to call the callback delegate.
|
||||||
|
/// </summary>
|
||||||
|
private object _state;
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the caller's context
|
||||||
|
/// </summary>
|
||||||
|
private readonly CallerThreadContext _callerContext;
|
||||||
|
#endif
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the result of the mehtod
|
||||||
|
/// </summary>
|
||||||
|
private object _result;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hold the exception if the method threw it
|
||||||
|
/// </summary>
|
||||||
|
private Exception _exception;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hold the state of the work item
|
||||||
|
/// </summary>
|
||||||
|
private WorkItemState _workItemState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A ManualResetEvent to indicate that the result is ready
|
||||||
|
/// </summary>
|
||||||
|
private ManualResetEvent _workItemCompleted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A reference count to the _workItemCompleted.
|
||||||
|
/// When it reaches to zero _workItemCompleted is Closed
|
||||||
|
/// </summary>
|
||||||
|
private int _workItemCompletedRefCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the result state of the work item
|
||||||
|
/// </summary>
|
||||||
|
private readonly WorkItemResult _workItemResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Work item info
|
||||||
|
/// </summary>
|
||||||
|
private readonly WorkItemInfo _workItemInfo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the WorkItem starts
|
||||||
|
/// </summary>
|
||||||
|
private event WorkItemStateCallback _workItemStartedEvent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the WorkItem completes
|
||||||
|
/// </summary>
|
||||||
|
private event WorkItemStateCallback _workItemCompletedEvent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A reference to an object that indicates whatever the
|
||||||
|
/// WorkItemsGroup has been canceled
|
||||||
|
/// </summary>
|
||||||
|
private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A reference to an object that indicates whatever the
|
||||||
|
/// SmartThreadPool has been canceled
|
||||||
|
/// </summary>
|
||||||
|
private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The work item group this work item belong to.
|
||||||
|
/// </summary>
|
||||||
|
private readonly IWorkItemsGroup _workItemsGroup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The thread that executes this workitem.
|
||||||
|
/// This field is available for the period when the work item is executed, before and after it is null.
|
||||||
|
/// </summary>
|
||||||
|
private Thread _executingThread;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The absulote time when the work item will be timeout
|
||||||
|
/// </summary>
|
||||||
|
private long _expirationTime;
|
||||||
|
|
||||||
|
#region Performance Counter fields
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores how long the work item waited on the stp queue
|
||||||
|
/// </summary>
|
||||||
|
private Stopwatch _waitingOnQueueStopwatch;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores how much time it took the work item to execute after it went out of the queue
|
||||||
|
/// </summary>
|
||||||
|
private Stopwatch _processingStopwatch;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public TimeSpan WaitingTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _waitingOnQueueStopwatch.Elapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeSpan ProcessTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _processingStopwatch.Elapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal WorkItemInfo WorkItemInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItemInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Construction
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize the callback holding object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The workItemGroup of the workitem</param>
|
||||||
|
/// <param name="workItemInfo">The WorkItemInfo of te workitem</param>
|
||||||
|
/// <param name="callback">Callback delegate for the callback.</param>
|
||||||
|
/// <param name="state">State with which to call the callback delegate.</param>
|
||||||
|
///
|
||||||
|
/// We assume that the WorkItem object is created within the thread
|
||||||
|
/// that meant to run the callback
|
||||||
|
public WorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WorkItemInfo workItemInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state)
|
||||||
|
{
|
||||||
|
_workItemsGroup = workItemsGroup;
|
||||||
|
_workItemInfo = workItemInfo;
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
|
||||||
|
{
|
||||||
|
_callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_callback = callback;
|
||||||
|
_state = state;
|
||||||
|
_workItemResult = new WorkItemResult(this);
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Initialize()
|
||||||
|
{
|
||||||
|
// The _workItemState is changed directly instead of using the SetWorkItemState
|
||||||
|
// method since we don't want to go throught IsValidStateTransition.
|
||||||
|
_workItemState = WorkItemState.InQueue;
|
||||||
|
|
||||||
|
_workItemCompleted = null;
|
||||||
|
_workItemCompletedRefCount = 0;
|
||||||
|
_waitingOnQueueStopwatch = new Stopwatch();
|
||||||
|
_processingStopwatch = new Stopwatch();
|
||||||
|
_expirationTime =
|
||||||
|
_workItemInfo.Timeout > 0 ?
|
||||||
|
DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond :
|
||||||
|
long.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
|
||||||
|
{
|
||||||
|
return (workItemsGroup == _workItemsGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
internal CanceledWorkItemsGroup CanceledWorkItemsGroup
|
||||||
|
{
|
||||||
|
get { return _canceledWorkItemsGroup; }
|
||||||
|
set { _canceledWorkItemsGroup = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal CanceledWorkItemsGroup CanceledSmartThreadPool
|
||||||
|
{
|
||||||
|
get { return _canceledSmartThreadPool; }
|
||||||
|
set { _canceledSmartThreadPool = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change the state of the work item to in progress if it wasn't canceled.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// Return true on success or false in case the work item was canceled.
|
||||||
|
/// If the work item needs to run a post execute then the method will return true.
|
||||||
|
/// </returns>
|
||||||
|
public bool StartingWorkItem()
|
||||||
|
{
|
||||||
|
_waitingOnQueueStopwatch.Stop();
|
||||||
|
_processingStopwatch.Start();
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (IsCanceled)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
if ((_workItemInfo.PostExecuteWorkItemCallback != null) &&
|
||||||
|
((_workItemInfo.CallToPostExecute & CallToPostExecute.WhenWorkItemCanceled) == CallToPostExecute.WhenWorkItemCanceled))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
|
||||||
|
|
||||||
|
// No need for a lock yet, only after the state has changed to InProgress
|
||||||
|
_executingThread = Thread.CurrentThread;
|
||||||
|
|
||||||
|
SetWorkItemState(WorkItemState.InProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute the work item and the post execute
|
||||||
|
/// </summary>
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
CallToPostExecute currentCallToPostExecute = 0;
|
||||||
|
|
||||||
|
// Execute the work item if we are in the correct state
|
||||||
|
switch (GetWorkItemState())
|
||||||
|
{
|
||||||
|
case WorkItemState.InProgress:
|
||||||
|
currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled;
|
||||||
|
ExecuteWorkItem();
|
||||||
|
break;
|
||||||
|
case WorkItemState.Canceled:
|
||||||
|
currentCallToPostExecute |= CallToPostExecute.WhenWorkItemCanceled;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug.Assert(false);
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the post execute as needed
|
||||||
|
if ((currentCallToPostExecute & _workItemInfo.CallToPostExecute) != 0)
|
||||||
|
{
|
||||||
|
PostExecute();
|
||||||
|
}
|
||||||
|
|
||||||
|
_processingStopwatch.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void FireWorkItemCompleted()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (null != _workItemCompletedEvent)
|
||||||
|
{
|
||||||
|
_workItemCompletedEvent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch // Suppress exceptions
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void FireWorkItemStarted()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (null != _workItemStartedEvent)
|
||||||
|
{
|
||||||
|
_workItemStartedEvent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch // Suppress exceptions
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute the work item
|
||||||
|
/// </summary>
|
||||||
|
private void ExecuteWorkItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
CallerThreadContext ctc = null;
|
||||||
|
if (null != _callerContext)
|
||||||
|
{
|
||||||
|
ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
|
||||||
|
CallerThreadContext.Apply(_callerContext);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Exception exception = null;
|
||||||
|
object result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = _callback(_state);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Save the exception so we can rethrow it later
|
||||||
|
exception = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the value of the execution thread, so it will be impossible to cancel the work item,
|
||||||
|
// since it is already completed.
|
||||||
|
// Cancelling a work item that already completed may cause the abortion of the next work item!!!
|
||||||
|
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||||
|
|
||||||
|
if (null == executionThread)
|
||||||
|
{
|
||||||
|
// Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException
|
||||||
|
Thread.Sleep(60 * 1000);
|
||||||
|
|
||||||
|
// If after 1 minute this thread was not aborted then let it continue working.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We must treat the ThreadAbortException or else it will be stored in the exception variable
|
||||||
|
catch (ThreadAbortException tae)
|
||||||
|
{
|
||||||
|
tae.GetHashCode();
|
||||||
|
// Check if the work item was cancelled
|
||||||
|
// If we got a ThreadAbortException and the STP is not shutting down, it means the
|
||||||
|
// work items was cancelled.
|
||||||
|
if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown)
|
||||||
|
{
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
Thread.ResetAbort();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
if (null != _callerContext)
|
||||||
|
{
|
||||||
|
CallerThreadContext.Apply(ctc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!SmartThreadPool.IsWorkItemCanceled)
|
||||||
|
{
|
||||||
|
SetResult(result, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the post execute callback
|
||||||
|
/// </summary>
|
||||||
|
private void PostExecute()
|
||||||
|
{
|
||||||
|
if (null != _workItemInfo.PostExecuteWorkItemCallback)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_workItemInfo.PostExecuteWorkItemCallback(_workItemResult);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Assert(null != e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the result of the work item to return
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The result of the work item</param>
|
||||||
|
/// <param name="exception">The exception that was throw while the workitem executed, null
|
||||||
|
/// if there was no exception.</param>
|
||||||
|
internal void SetResult(object result, Exception exception)
|
||||||
|
{
|
||||||
|
_result = result;
|
||||||
|
_exception = exception;
|
||||||
|
SignalComplete(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the work item result
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The work item result</returns>
|
||||||
|
internal IWorkItemResult GetWorkItemResult()
|
||||||
|
{
|
||||||
|
return _workItemResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for all work items to complete
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="waitableResults">Array of work item result objects</param>
|
||||||
|
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
||||||
|
/// <param name="exitContext">
|
||||||
|
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
|
||||||
|
/// <returns>
|
||||||
|
/// true when every work item in waitableResults has completed; otherwise false.
|
||||||
|
/// </returns>
|
||||||
|
internal static bool WaitAll(
|
||||||
|
IWaitableResult[] waitableResults,
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle)
|
||||||
|
{
|
||||||
|
if (0 == waitableResults.Length)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success;
|
||||||
|
WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
|
||||||
|
GetWaitHandles(waitableResults, waitHandles);
|
||||||
|
|
||||||
|
if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
|
||||||
|
{
|
||||||
|
success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
int millisecondsLeft = millisecondsTimeout;
|
||||||
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
WaitHandle[] whs;
|
||||||
|
if (null != cancelWaitHandle)
|
||||||
|
{
|
||||||
|
whs = new WaitHandle[] { null, cancelWaitHandle };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
whs = new WaitHandle[] { null };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
|
||||||
|
// Iterate over the wait handles and wait for each one to complete.
|
||||||
|
// We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
|
||||||
|
// won't affect it.
|
||||||
|
// Each iteration we update the time left for the timeout.
|
||||||
|
for (int i = 0; i < waitableResults.Length; ++i)
|
||||||
|
{
|
||||||
|
// WaitAny don't work with negative numbers
|
||||||
|
if (!waitInfinitely && (millisecondsLeft < 0))
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
whs[0] = waitHandles[i];
|
||||||
|
int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
|
||||||
|
if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result))
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!waitInfinitely)
|
||||||
|
{
|
||||||
|
// Update the time left to wait
|
||||||
|
millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Release the wait handles
|
||||||
|
ReleaseWaitHandles(waitableResults);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits for any of the work items in the specified array to complete, cancel, or timeout
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="waitableResults">Array of work item result objects</param>
|
||||||
|
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
||||||
|
/// <param name="exitContext">
|
||||||
|
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
|
||||||
|
/// </returns>
|
||||||
|
internal static int WaitAny(
|
||||||
|
IWaitableResult[] waitableResults,
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle)
|
||||||
|
{
|
||||||
|
WaitHandle[] waitHandles;
|
||||||
|
|
||||||
|
if (null != cancelWaitHandle)
|
||||||
|
{
|
||||||
|
waitHandles = new WaitHandle[waitableResults.Length + 1];
|
||||||
|
GetWaitHandles(waitableResults, waitHandles);
|
||||||
|
waitHandles[waitableResults.Length] = cancelWaitHandle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waitHandles = new WaitHandle[waitableResults.Length];
|
||||||
|
GetWaitHandles(waitableResults, waitHandles);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
|
||||||
|
|
||||||
|
// Treat cancel as timeout
|
||||||
|
if (null != cancelWaitHandle)
|
||||||
|
{
|
||||||
|
if (result == waitableResults.Length)
|
||||||
|
{
|
||||||
|
result = STPEventWaitHandle.WaitTimeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseWaitHandles(waitableResults);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fill an array of wait handles with the work items wait handles.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="waitableResults">An array of work item results</param>
|
||||||
|
/// <param name="waitHandles">An array of wait handles to fill</param>
|
||||||
|
private static void GetWaitHandles(
|
||||||
|
IWaitableResult[] waitableResults,
|
||||||
|
WaitHandle[] waitHandles)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < waitableResults.Length; ++i)
|
||||||
|
{
|
||||||
|
WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult;
|
||||||
|
Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects");
|
||||||
|
|
||||||
|
waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Release the work items' wait handles
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="waitableResults">An array of work item results</param>
|
||||||
|
private static void ReleaseWaitHandles(IWaitableResult[] waitableResults)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < waitableResults.Length; ++i)
|
||||||
|
{
|
||||||
|
WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult();
|
||||||
|
|
||||||
|
wir.GetWorkItem().ReleaseWaitHandle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Members
|
||||||
|
|
||||||
|
private WorkItemState GetWorkItemState()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (WorkItemState.Completed == _workItemState)
|
||||||
|
{
|
||||||
|
return _workItemState;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nowTicks = DateTime.UtcNow.Ticks;
|
||||||
|
|
||||||
|
if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime)
|
||||||
|
{
|
||||||
|
_workItemState = WorkItemState.Canceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WorkItemState.InProgress == _workItemState)
|
||||||
|
{
|
||||||
|
return _workItemState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled)
|
||||||
|
{
|
||||||
|
return WorkItemState.Canceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _workItemState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the work item's state
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemState">The state to set the work item to</param>
|
||||||
|
private void SetWorkItemState(WorkItemState workItemState)
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (IsValidStatesTransition(_workItemState, workItemState))
|
||||||
|
{
|
||||||
|
_workItemState = workItemState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signals that work item has been completed or canceled
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="canceled">Indicates that the work item has been canceled</param>
|
||||||
|
private void SignalComplete(bool canceled)
|
||||||
|
{
|
||||||
|
SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed);
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
// If someone is waiting then signal.
|
||||||
|
if (null != _workItemCompleted)
|
||||||
|
{
|
||||||
|
_workItemCompleted.Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WorkItemIsQueued()
|
||||||
|
{
|
||||||
|
_waitingOnQueueStopwatch.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Members exposed by WorkItemResult
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel the work item if it didn't start running yet.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
|
||||||
|
private bool Cancel(bool abortExecution)
|
||||||
|
{
|
||||||
|
#if (_WINDOWS_CE)
|
||||||
|
if(abortExecution)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
bool success = false;
|
||||||
|
bool signalComplete = false;
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
switch (GetWorkItemState())
|
||||||
|
{
|
||||||
|
case WorkItemState.Canceled:
|
||||||
|
//Debug.WriteLine("Work item already canceled");
|
||||||
|
if (abortExecution)
|
||||||
|
{
|
||||||
|
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||||
|
if (null != executionThread)
|
||||||
|
{
|
||||||
|
executionThread.Abort(); // "Cancel"
|
||||||
|
// No need to signalComplete, because we already cancelled this work item
|
||||||
|
// so it already signaled its completion.
|
||||||
|
//signalComplete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
case WorkItemState.Completed:
|
||||||
|
//Debug.WriteLine("Work item cannot be canceled");
|
||||||
|
break;
|
||||||
|
case WorkItemState.InProgress:
|
||||||
|
if (abortExecution)
|
||||||
|
{
|
||||||
|
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||||
|
if (null != executionThread)
|
||||||
|
{
|
||||||
|
executionThread.Abort(); // "Cancel"
|
||||||
|
success = true;
|
||||||
|
signalComplete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
signalComplete = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WorkItemState.InQueue:
|
||||||
|
// Signal to the wait for completion that the work
|
||||||
|
// item has been completed (canceled). There is no
|
||||||
|
// reason to wait for it to get out of the queue
|
||||||
|
signalComplete = true;
|
||||||
|
//Debug.WriteLine("Work item canceled");
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signalComplete)
|
||||||
|
{
|
||||||
|
SignalComplete(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits for the result, timeout, or cancel.
|
||||||
|
/// In case of error the method throws and exception
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
private object GetResult(
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle)
|
||||||
|
{
|
||||||
|
Exception e;
|
||||||
|
object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
||||||
|
if (null != e)
|
||||||
|
{
|
||||||
|
throw new WorkItemResultException("The work item caused an excpetion, see the inner exception for details", e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the result of the work item.
|
||||||
|
/// If the work item didn't run yet then the caller waits for the result, timeout, or cancel.
|
||||||
|
/// In case of error the e argument is filled with the exception
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The result of the work item</returns>
|
||||||
|
private object GetResult(
|
||||||
|
int millisecondsTimeout,
|
||||||
|
bool exitContext,
|
||||||
|
WaitHandle cancelWaitHandle,
|
||||||
|
out Exception e)
|
||||||
|
{
|
||||||
|
e = null;
|
||||||
|
|
||||||
|
// Check for cancel
|
||||||
|
if (WorkItemState.Canceled == GetWorkItemState())
|
||||||
|
{
|
||||||
|
throw new WorkItemCancelException("Work item canceled");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for completion
|
||||||
|
if (IsCompleted)
|
||||||
|
{
|
||||||
|
e = _exception;
|
||||||
|
return _result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no cancelWaitHandle is provided
|
||||||
|
if (null == cancelWaitHandle)
|
||||||
|
{
|
||||||
|
WaitHandle wh = GetWaitHandle();
|
||||||
|
|
||||||
|
bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext);
|
||||||
|
|
||||||
|
ReleaseWaitHandle();
|
||||||
|
|
||||||
|
if (timeout)
|
||||||
|
{
|
||||||
|
throw new WorkItemTimeoutException("Work item timeout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WaitHandle wh = GetWaitHandle();
|
||||||
|
int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
|
||||||
|
ReleaseWaitHandle();
|
||||||
|
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
// The work item signaled
|
||||||
|
// Note that the signal could be also as a result of canceling the
|
||||||
|
// work item (not the get result)
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case STPEventWaitHandle.WaitTimeout:
|
||||||
|
throw new WorkItemTimeoutException("Work item timeout");
|
||||||
|
default:
|
||||||
|
Debug.Assert(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for cancel
|
||||||
|
if (WorkItemState.Canceled == GetWorkItemState())
|
||||||
|
{
|
||||||
|
throw new WorkItemCancelException("Work item canceled");
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(IsCompleted);
|
||||||
|
|
||||||
|
e = _exception;
|
||||||
|
|
||||||
|
// Return the result
|
||||||
|
return _result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A wait handle to wait for completion, cancel, or timeout
|
||||||
|
/// </summary>
|
||||||
|
private WaitHandle GetWaitHandle()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (null == _workItemCompleted)
|
||||||
|
{
|
||||||
|
_workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
|
||||||
|
}
|
||||||
|
++_workItemCompletedRefCount;
|
||||||
|
}
|
||||||
|
return _workItemCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleaseWaitHandle()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (null != _workItemCompleted)
|
||||||
|
{
|
||||||
|
--_workItemCompletedRefCount;
|
||||||
|
if (0 == _workItemCompletedRefCount)
|
||||||
|
{
|
||||||
|
_workItemCompleted.Close();
|
||||||
|
_workItemCompleted = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true when the work item has completed or canceled
|
||||||
|
/// </summary>
|
||||||
|
private bool IsCompleted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
WorkItemState workItemState = GetWorkItemState();
|
||||||
|
return ((workItemState == WorkItemState.Completed) ||
|
||||||
|
(workItemState == WorkItemState.Canceled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true when the work item has canceled
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCanceled
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
return (GetWorkItemState() == WorkItemState.Canceled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IHasWorkItemPriority Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the priority of the work item
|
||||||
|
/// </summary>
|
||||||
|
public WorkItemPriority WorkItemPriority
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItemInfo.WorkItemPriority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
internal event WorkItemStateCallback OnWorkItemStarted
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
_workItemStartedEvent += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_workItemStartedEvent -= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal event WorkItemStateCallback OnWorkItemCompleted
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
_workItemCompletedEvent += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_workItemCompletedEvent -= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisposeOfState()
|
||||||
|
{
|
||||||
|
if (_workItemInfo.DisposeOfStateObjects)
|
||||||
|
{
|
||||||
|
IDisposable disp = _state as IDisposable;
|
||||||
|
if (null != disp)
|
||||||
|
{
|
||||||
|
disp.Dispose();
|
||||||
|
_state = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
343
Networking/SmartThreadPool/WorkItemFactory.cs
Normal file
343
Networking/SmartThreadPool/WorkItemFactory.cs
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
#region WorkItemFactory class
|
||||||
|
|
||||||
|
public class WorkItemFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback)
|
||||||
|
{
|
||||||
|
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="workItemPriority">The priority of the work item</param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="workItemInfo">Work item info</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemInfo workItemInfo,
|
||||||
|
WorkItemCallback callback)
|
||||||
|
{
|
||||||
|
return CreateWorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
wigStartInfo,
|
||||||
|
workItemInfo,
|
||||||
|
callback,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state)
|
||||||
|
{
|
||||||
|
ValidateCallback(callback);
|
||||||
|
|
||||||
|
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||||
|
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
|
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
|
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||||
|
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
|
||||||
|
WorkItem workItem = new WorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
workItemInfo,
|
||||||
|
callback,
|
||||||
|
state);
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
ValidateCallback(callback);
|
||||||
|
|
||||||
|
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||||
|
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
|
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
|
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||||
|
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = workItemPriority;
|
||||||
|
|
||||||
|
WorkItem workItem = new WorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
workItemInfo,
|
||||||
|
callback,
|
||||||
|
state);
|
||||||
|
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="workItemInfo">Work item information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemInfo workItemInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state)
|
||||||
|
{
|
||||||
|
ValidateCallback(callback);
|
||||||
|
ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
|
||||||
|
|
||||||
|
WorkItem workItem = new WorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
new WorkItemInfo(workItemInfo),
|
||||||
|
callback,
|
||||||
|
state);
|
||||||
|
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback)
|
||||||
|
{
|
||||||
|
ValidateCallback(callback);
|
||||||
|
ValidateCallback(postExecuteWorkItemCallback);
|
||||||
|
|
||||||
|
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||||
|
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
|
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
|
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||||
|
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
|
||||||
|
WorkItem workItem = new WorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
workItemInfo,
|
||||||
|
callback,
|
||||||
|
state);
|
||||||
|
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||||
|
WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
ValidateCallback(callback);
|
||||||
|
ValidateCallback(postExecuteWorkItemCallback);
|
||||||
|
|
||||||
|
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||||
|
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
|
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
|
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||||
|
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = workItemPriority;
|
||||||
|
|
||||||
|
WorkItem workItem = new WorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
workItemInfo,
|
||||||
|
callback,
|
||||||
|
state);
|
||||||
|
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||||
|
CallToPostExecute callToPostExecute)
|
||||||
|
{
|
||||||
|
ValidateCallback(callback);
|
||||||
|
ValidateCallback(postExecuteWorkItemCallback);
|
||||||
|
|
||||||
|
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||||
|
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
|
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
|
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||||
|
workItemInfo.CallToPostExecute = callToPostExecute;
|
||||||
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
|
||||||
|
WorkItem workItem = new WorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
workItemInfo,
|
||||||
|
callback,
|
||||||
|
state);
|
||||||
|
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item</returns>
|
||||||
|
public static WorkItem CreateWorkItem(
|
||||||
|
IWorkItemsGroup workItemsGroup,
|
||||||
|
WIGStartInfo wigStartInfo,
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||||
|
CallToPostExecute callToPostExecute,
|
||||||
|
WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
|
||||||
|
ValidateCallback(callback);
|
||||||
|
ValidateCallback(postExecuteWorkItemCallback);
|
||||||
|
|
||||||
|
WorkItemInfo workItemInfo = new WorkItemInfo();
|
||||||
|
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
|
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
|
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||||
|
workItemInfo.CallToPostExecute = callToPostExecute;
|
||||||
|
workItemInfo.WorkItemPriority = workItemPriority;
|
||||||
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
|
||||||
|
WorkItem workItem = new WorkItem(
|
||||||
|
workItemsGroup,
|
||||||
|
workItemInfo,
|
||||||
|
callback,
|
||||||
|
state);
|
||||||
|
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateCallback(Delegate callback)
|
||||||
|
{
|
||||||
|
if (callback != null && callback.GetInvocationList().Length > 1)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
69
Networking/SmartThreadPool/WorkItemInfo.cs
Normal file
69
Networking/SmartThreadPool/WorkItemInfo.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
#region WorkItemInfo class
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Summary description for WorkItemInfo.
|
||||||
|
/// </summary>
|
||||||
|
public class WorkItemInfo
|
||||||
|
{
|
||||||
|
public WorkItemInfo()
|
||||||
|
{
|
||||||
|
UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||||
|
UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||||
|
DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||||
|
CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||||
|
PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||||
|
WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemInfo(WorkItemInfo workItemInfo)
|
||||||
|
{
|
||||||
|
UseCallerCallContext = workItemInfo.UseCallerCallContext;
|
||||||
|
UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
|
||||||
|
DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
|
||||||
|
CallToPostExecute = workItemInfo.CallToPostExecute;
|
||||||
|
PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
|
||||||
|
WorkItemPriority = workItemInfo.WorkItemPriority;
|
||||||
|
Timeout = workItemInfo.Timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to use the caller's security context
|
||||||
|
/// </summary>
|
||||||
|
public bool UseCallerCallContext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to use the caller's HTTP context
|
||||||
|
/// </summary>
|
||||||
|
public bool UseCallerHttpContext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to dispose of the state object of a work item
|
||||||
|
/// </summary>
|
||||||
|
public bool DisposeOfStateObjects { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the run the post execute options
|
||||||
|
/// </summary>
|
||||||
|
public CallToPostExecute CallToPostExecute { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the post execute callback
|
||||||
|
/// </summary>
|
||||||
|
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the work item's priority
|
||||||
|
/// </summary>
|
||||||
|
public WorkItemPriority WorkItemPriority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the work item's timout in milliseconds.
|
||||||
|
/// This is a passive timout. When the timout expires the work item won't be actively aborted!
|
||||||
|
/// </summary>
|
||||||
|
public long Timeout { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
128
Networking/SmartThreadPool/WorkItemResultTWrapper.cs
Normal file
128
Networking/SmartThreadPool/WorkItemResultTWrapper.cs
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
#region WorkItemResultTWrapper class
|
||||||
|
|
||||||
|
internal class WorkItemResultTWrapper<TResult> : IWorkItemResult<TResult>, IInternalWaitableResult
|
||||||
|
{
|
||||||
|
private readonly IWorkItemResult _workItemResult;
|
||||||
|
|
||||||
|
public WorkItemResultTWrapper(IWorkItemResult workItemResult)
|
||||||
|
{
|
||||||
|
_workItemResult = workItemResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IWorkItemResult<TResult> Members
|
||||||
|
|
||||||
|
public TResult GetResult()
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(int millisecondsTimeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(TimeSpan timeout, bool exitContext)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(timeout, exitContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(out Exception e)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(timeout, exitContext, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
|
||||||
|
{
|
||||||
|
return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCompleted
|
||||||
|
{
|
||||||
|
get { return _workItemResult.IsCompleted; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCanceled
|
||||||
|
{
|
||||||
|
get { return _workItemResult.IsCanceled; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public object State
|
||||||
|
{
|
||||||
|
get { return _workItemResult.State; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Cancel()
|
||||||
|
{
|
||||||
|
return _workItemResult.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Cancel(bool abortExecution)
|
||||||
|
{
|
||||||
|
return _workItemResult.Cancel(abortExecution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemPriority WorkItemPriority
|
||||||
|
{
|
||||||
|
get { return _workItemResult.WorkItemPriority; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult Result
|
||||||
|
{
|
||||||
|
get { return (TResult)_workItemResult.Result; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Exception
|
||||||
|
{
|
||||||
|
get { return _workItemResult.Exception; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IInternalWorkItemResult Members
|
||||||
|
|
||||||
|
public IWorkItemResult GetWorkItemResult()
|
||||||
|
{
|
||||||
|
return _workItemResult.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult<TRes> GetWorkItemResultT<TRes>()
|
||||||
|
{
|
||||||
|
return (IWorkItemResult<TRes>)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
369
Networking/SmartThreadPool/WorkItemsGroup.cs
Normal file
369
Networking/SmartThreadPool/WorkItemsGroup.cs
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
|
||||||
|
#region WorkItemsGroup class
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Summary description for WorkItemsGroup.
|
||||||
|
/// </summary>
|
||||||
|
public class WorkItemsGroup : WorkItemsGroupBase
|
||||||
|
{
|
||||||
|
#region Private members
|
||||||
|
|
||||||
|
private readonly object _lock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A reference to the SmartThreadPool instance that created this
|
||||||
|
/// WorkItemsGroup.
|
||||||
|
/// </summary>
|
||||||
|
private readonly SmartThreadPool _stp;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The OnIdle event
|
||||||
|
/// </summary>
|
||||||
|
private event WorkItemsGroupIdleHandler _onIdle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A flag to indicate if the Work Items Group is now suspended.
|
||||||
|
/// </summary>
|
||||||
|
private bool _isSuspended;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines how many work items of this WorkItemsGroup can run at once.
|
||||||
|
/// </summary>
|
||||||
|
private int _concurrency;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Priority queue to hold work items before they are passed
|
||||||
|
/// to the SmartThreadPool.
|
||||||
|
/// </summary>
|
||||||
|
private readonly PriorityQueue _workItemsQueue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicate how many work items are waiting in the SmartThreadPool
|
||||||
|
/// queue.
|
||||||
|
/// This value is used to apply the concurrency.
|
||||||
|
/// </summary>
|
||||||
|
private int _workItemsInStpQueue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicate how many work items are currently running in the SmartThreadPool.
|
||||||
|
/// This value is used with the Cancel, to calculate if we can send new
|
||||||
|
/// work items to the STP.
|
||||||
|
/// </summary>
|
||||||
|
private int _workItemsExecutingInStp = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WorkItemsGroup start information
|
||||||
|
/// </summary>
|
||||||
|
private readonly WIGStartInfo _workItemsGroupStartInfo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signaled when all of the WorkItemsGroup's work item completed.
|
||||||
|
/// </summary>
|
||||||
|
//private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
|
||||||
|
private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A common object for all the work items that this work items group
|
||||||
|
/// generate so we can mark them to cancel in O(1)
|
||||||
|
/// </summary>
|
||||||
|
private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Construction
|
||||||
|
|
||||||
|
public WorkItemsGroup(
|
||||||
|
SmartThreadPool stp,
|
||||||
|
int concurrency,
|
||||||
|
WIGStartInfo wigStartInfo)
|
||||||
|
{
|
||||||
|
if (concurrency <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
"concurrency",
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
concurrency,
|
||||||
|
#endif
|
||||||
|
"concurrency must be greater than zero");
|
||||||
|
}
|
||||||
|
_stp = stp;
|
||||||
|
_concurrency = concurrency;
|
||||||
|
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
|
||||||
|
_workItemsQueue = new PriorityQueue();
|
||||||
|
Name = "WorkItemsGroup";
|
||||||
|
|
||||||
|
// The _workItemsInStpQueue gets the number of currently executing work items,
|
||||||
|
// because once a work item is executing, it cannot be cancelled.
|
||||||
|
_workItemsInStpQueue = _workItemsExecutingInStp;
|
||||||
|
|
||||||
|
_isSuspended = _workItemsGroupStartInfo.StartSuspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region WorkItemsGroupBase Overrides
|
||||||
|
|
||||||
|
public override int Concurrency
|
||||||
|
{
|
||||||
|
get { return _concurrency; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Debug.Assert(value > 0);
|
||||||
|
|
||||||
|
int diff = value - _concurrency;
|
||||||
|
_concurrency = value;
|
||||||
|
if (diff > 0)
|
||||||
|
{
|
||||||
|
EnqueueToSTPNextNWorkItem(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int InUseThreads
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItemsExecutingInStp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int WaitingCallbacks
|
||||||
|
{
|
||||||
|
get { return _workItemsQueue.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object[] GetStates()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
object[] states = new object[_workItemsQueue.Count];
|
||||||
|
int i = 0;
|
||||||
|
foreach (WorkItem workItem in _workItemsQueue)
|
||||||
|
{
|
||||||
|
states[i] = workItem.GetWorkItemResult().State;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return states;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WorkItemsGroup start information
|
||||||
|
/// </summary>
|
||||||
|
public override WIGStartInfo WIGStartInfo
|
||||||
|
{
|
||||||
|
get { return _workItemsGroupStartInfo; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start the Work Items Group if it was started suspended
|
||||||
|
/// </summary>
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
// If the Work Items Group already started then quit
|
||||||
|
if (!_isSuspended)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isSuspended = false;
|
||||||
|
|
||||||
|
EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Cancel(bool abortExecution)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_canceledWorkItemsGroup.IsCanceled = true;
|
||||||
|
_workItemsQueue.Clear();
|
||||||
|
_workItemsInStpQueue = 0;
|
||||||
|
_canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abortExecution)
|
||||||
|
{
|
||||||
|
_stp.CancelAbortWorkItemsGroup(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for the thread pool to be idle
|
||||||
|
/// </summary>
|
||||||
|
public override bool WaitForIdle(int millisecondsTimeout)
|
||||||
|
{
|
||||||
|
SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
|
||||||
|
return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override event WorkItemsGroupIdleHandler OnIdle
|
||||||
|
{
|
||||||
|
add { _onIdle += value; }
|
||||||
|
remove { _onIdle -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private methods
|
||||||
|
|
||||||
|
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
|
||||||
|
{
|
||||||
|
IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
|
||||||
|
iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
|
||||||
|
iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSTPIsStarting()
|
||||||
|
{
|
||||||
|
if (_isSuspended)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnqueueToSTPNextNWorkItem(_concurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnqueueToSTPNextNWorkItem(int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
EnqueueToSTPNextWorkItem(null, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object FireOnIdle(object state)
|
||||||
|
{
|
||||||
|
FireOnIdleImpl(_onIdle);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
|
||||||
|
{
|
||||||
|
if(null == onIdle)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate[] delegates = onIdle.GetInvocationList();
|
||||||
|
foreach(WorkItemsGroupIdleHandler eh in delegates)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
eh(this);
|
||||||
|
}
|
||||||
|
catch { } // Suppress exceptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWorkItemStartedCallback(WorkItem workItem)
|
||||||
|
{
|
||||||
|
lock(_lock)
|
||||||
|
{
|
||||||
|
++_workItemsExecutingInStp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWorkItemCompletedCallback(WorkItem workItem)
|
||||||
|
{
|
||||||
|
EnqueueToSTPNextWorkItem(null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Enqueue(WorkItem workItem)
|
||||||
|
{
|
||||||
|
EnqueueToSTPNextWorkItem(workItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
|
||||||
|
{
|
||||||
|
EnqueueToSTPNextWorkItem(workItem, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
|
||||||
|
{
|
||||||
|
lock(_lock)
|
||||||
|
{
|
||||||
|
// Got here from OnWorkItemCompletedCallback()
|
||||||
|
if (decrementWorkItemsInStpQueue)
|
||||||
|
{
|
||||||
|
--_workItemsInStpQueue;
|
||||||
|
|
||||||
|
if(_workItemsInStpQueue < 0)
|
||||||
|
{
|
||||||
|
_workItemsInStpQueue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
--_workItemsExecutingInStp;
|
||||||
|
|
||||||
|
if(_workItemsExecutingInStp < 0)
|
||||||
|
{
|
||||||
|
_workItemsExecutingInStp = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the work item is not null then enqueue it
|
||||||
|
if (null != workItem)
|
||||||
|
{
|
||||||
|
workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
|
||||||
|
|
||||||
|
RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
|
||||||
|
_workItemsQueue.Enqueue(workItem);
|
||||||
|
//_stp.IncrementWorkItemsCount();
|
||||||
|
|
||||||
|
if ((1 == _workItemsQueue.Count) &&
|
||||||
|
(0 == _workItemsInStpQueue))
|
||||||
|
{
|
||||||
|
_stp.RegisterWorkItemsGroup(this);
|
||||||
|
IsIdle = false;
|
||||||
|
_isIdleWaitHandle.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the work items queue of the group is empty than quit
|
||||||
|
if (0 == _workItemsQueue.Count)
|
||||||
|
{
|
||||||
|
if (0 == _workItemsInStpQueue)
|
||||||
|
{
|
||||||
|
_stp.UnregisterWorkItemsGroup(this);
|
||||||
|
IsIdle = true;
|
||||||
|
_isIdleWaitHandle.Set();
|
||||||
|
if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
|
||||||
|
{
|
||||||
|
_stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isSuspended)
|
||||||
|
{
|
||||||
|
if (_workItemsInStpQueue < _concurrency)
|
||||||
|
{
|
||||||
|
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_stp.Enqueue(nextWorkItem);
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException e)
|
||||||
|
{
|
||||||
|
e.GetHashCode();
|
||||||
|
// The STP has been shutdown
|
||||||
|
}
|
||||||
|
|
||||||
|
++_workItemsInStpQueue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
449
Networking/SmartThreadPool/WorkItemsGroupBase.cs
Normal file
449
Networking/SmartThreadPool/WorkItemsGroupBase.cs
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
public abstract class WorkItemsGroupBase : IWorkItemsGroup
|
||||||
|
{
|
||||||
|
#region Private Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the name of this instance of SmartThreadPool.
|
||||||
|
/// Can be changed by the user.
|
||||||
|
/// </summary>
|
||||||
|
private string _name = "WorkItemsGroupBase";
|
||||||
|
|
||||||
|
public WorkItemsGroupBase()
|
||||||
|
{
|
||||||
|
IsIdle = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IWorkItemsGroup Members
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance
|
||||||
|
/// </summary>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return _name; }
|
||||||
|
set { _name = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Abstract Methods
|
||||||
|
|
||||||
|
public abstract int Concurrency { get; set; }
|
||||||
|
public abstract int WaitingCallbacks { get; }
|
||||||
|
public abstract int InUseThreads { get; }
|
||||||
|
|
||||||
|
public abstract object[] GetStates();
|
||||||
|
public abstract WIGStartInfo WIGStartInfo { get; }
|
||||||
|
public abstract void Start();
|
||||||
|
public abstract void Cancel(bool abortExecution);
|
||||||
|
public abstract bool WaitForIdle(int millisecondsTimeout);
|
||||||
|
public abstract event WorkItemsGroupIdleHandler OnIdle;
|
||||||
|
|
||||||
|
internal abstract void Enqueue(WorkItem workItem);
|
||||||
|
internal virtual void PreQueueWorkItem() { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Common Base Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel all the work items.
|
||||||
|
/// Same as Cancel(false)
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Cancel()
|
||||||
|
{
|
||||||
|
Cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
|
||||||
|
/// </summary>
|
||||||
|
public void WaitForIdle()
|
||||||
|
{
|
||||||
|
WaitForIdle(Timeout.Infinite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
|
||||||
|
/// </summary>
|
||||||
|
public bool WaitForIdle(TimeSpan timeout)
|
||||||
|
{
|
||||||
|
return WaitForIdle((int)timeout.TotalMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IsIdle is true when there are no work items running or queued.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsIdle { get; protected set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region QueueWorkItem
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
|
||||||
|
{
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="workItemPriority">The priority of the work item</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemInfo">Work item info</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
|
||||||
|
{
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="workItemInfo">Work item information</param>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||||
|
WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||||
|
CallToPostExecute callToPostExecute)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <param name="state">
|
||||||
|
/// The context object of the work item. Used for passing arguments to the work item.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="postExecuteWorkItemCallback">
|
||||||
|
/// A delegate to call after the callback completion
|
||||||
|
/// </param>
|
||||||
|
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
|
||||||
|
/// <param name="workItemPriority">The work item priority</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
public IWorkItemResult QueueWorkItem(
|
||||||
|
WorkItemCallback callback,
|
||||||
|
object state,
|
||||||
|
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
|
||||||
|
CallToPostExecute callToPostExecute,
|
||||||
|
WorkItemPriority workItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return workItem.GetWorkItemResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region QueueWorkItem(Action<...>)
|
||||||
|
|
||||||
|
public IWorkItemResult QueueWorkItem(Action action, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem ();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
delegate
|
||||||
|
{
|
||||||
|
action.Invoke ();
|
||||||
|
return null;
|
||||||
|
}, priority);
|
||||||
|
Enqueue (workItem);
|
||||||
|
return workItem.GetWorkItemResult ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem ();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
action.Invoke (arg);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority);
|
||||||
|
Enqueue (workItem);
|
||||||
|
return workItem.GetWorkItemResult ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem ();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
action.Invoke (arg1, arg2);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority);
|
||||||
|
Enqueue (workItem);
|
||||||
|
return workItem.GetWorkItemResult ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem ();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
action.Invoke (arg1, arg2, arg3);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority);
|
||||||
|
Enqueue (workItem);
|
||||||
|
return workItem.GetWorkItemResult ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (
|
||||||
|
Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem ();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem (
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
action.Invoke (arg1, arg2, arg3, arg4);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority);
|
||||||
|
Enqueue (workItem);
|
||||||
|
return workItem.GetWorkItemResult ();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region QueueWorkItem(Func<...>)
|
||||||
|
|
||||||
|
public IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
return func.Invoke();
|
||||||
|
}, priority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
return func.Invoke(arg);
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null,
|
||||||
|
priority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
return func.Invoke(arg1, arg2);
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null,
|
||||||
|
priority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(
|
||||||
|
Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
return func.Invoke(arg1, arg2, arg3);
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null,
|
||||||
|
priority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(
|
||||||
|
Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority = SmartThreadPool.DefaultWorkItemPriority)
|
||||||
|
{
|
||||||
|
PreQueueWorkItem();
|
||||||
|
WorkItem workItem = WorkItemFactory.CreateWorkItem(
|
||||||
|
this,
|
||||||
|
WIGStartInfo,
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
return func.Invoke(arg1, arg2, arg3, arg4);
|
||||||
|
},
|
||||||
|
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null,
|
||||||
|
priority);
|
||||||
|
Enqueue(workItem);
|
||||||
|
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
645
Networking/SmartThreadPool/WorkItemsQueue.cs
Normal file
645
Networking/SmartThreadPool/WorkItemsQueue.cs
Normal file
@@ -0,0 +1,645 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading.Internal
|
||||||
|
{
|
||||||
|
#region WorkItemsQueue class
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WorkItemsQueue class.
|
||||||
|
/// </summary>
|
||||||
|
public class WorkItemsQueue : IDisposable
|
||||||
|
{
|
||||||
|
#region Member variables
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waiters queue (implemented as stack).
|
||||||
|
/// </summary>
|
||||||
|
private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waiters count
|
||||||
|
/// </summary>
|
||||||
|
private int _waitersCount = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Work items queue
|
||||||
|
/// </summary>
|
||||||
|
private readonly PriorityQueue _workItems = new PriorityQueue();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicate that work items are allowed to be queued
|
||||||
|
/// </summary>
|
||||||
|
private bool _isWorkItemsQueueActive = true;
|
||||||
|
|
||||||
|
|
||||||
|
#if (WINDOWS_PHONE)
|
||||||
|
private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>();
|
||||||
|
#elif (_WINDOWS_CE)
|
||||||
|
private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
|
||||||
|
#else
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static WaiterEntry _waiterEntry;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Each thread in the thread pool keeps its own waiter entry.
|
||||||
|
/// </summary>
|
||||||
|
private static WaiterEntry CurrentWaiterEntry
|
||||||
|
{
|
||||||
|
#if (WINDOWS_PHONE)
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_waiterEntries)
|
||||||
|
{
|
||||||
|
WaiterEntry waiterEntry;
|
||||||
|
if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry))
|
||||||
|
{
|
||||||
|
return waiterEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
lock (_waiterEntries)
|
||||||
|
{
|
||||||
|
_waiterEntries[Thread.CurrentThread.ManagedThreadId] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif (_WINDOWS_CE)
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Thread.SetData(_waiterEntrySlot, value);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _waiterEntry;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_waiterEntry = value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A flag that indicates if the WorkItemsQueue has been disposed.
|
||||||
|
/// </summary>
|
||||||
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current number of work items in the queue
|
||||||
|
/// </summary>
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItems.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current number of waiters
|
||||||
|
/// </summary>
|
||||||
|
public int WaitersCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _waitersCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enqueue a work item to the queue.
|
||||||
|
/// </summary>
|
||||||
|
public bool EnqueueWorkItem(WorkItem workItem)
|
||||||
|
{
|
||||||
|
// A work item cannot be null, since null is used in the
|
||||||
|
// WaitForWorkItem() method to indicate timeout or cancel
|
||||||
|
if (null == workItem)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("workItem" , "workItem cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enqueue = true;
|
||||||
|
|
||||||
|
// First check if there is a waiter waiting for work item. During
|
||||||
|
// the check, timed out waiters are ignored. If there is no
|
||||||
|
// waiter then the work item is queued.
|
||||||
|
lock(this)
|
||||||
|
{
|
||||||
|
ValidateNotDisposed();
|
||||||
|
|
||||||
|
if (!_isWorkItemsQueueActive)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(_waitersCount > 0)
|
||||||
|
{
|
||||||
|
// Dequeue a waiter.
|
||||||
|
WaiterEntry waiterEntry = PopWaiter();
|
||||||
|
|
||||||
|
// Signal the waiter. On success break the loop
|
||||||
|
if (waiterEntry.Signal(workItem))
|
||||||
|
{
|
||||||
|
enqueue = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enqueue)
|
||||||
|
{
|
||||||
|
// Enqueue the work item
|
||||||
|
_workItems.Enqueue(workItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits for a work item or exits on timeout or cancel
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="millisecondsTimeout">Timeout in milliseconds</param>
|
||||||
|
/// <param name="cancelEvent">Cancel wait handle</param>
|
||||||
|
/// <returns>Returns true if the resource was granted</returns>
|
||||||
|
public WorkItem DequeueWorkItem(
|
||||||
|
int millisecondsTimeout,
|
||||||
|
WaitHandle cancelEvent)
|
||||||
|
{
|
||||||
|
// This method cause the caller to wait for a work item.
|
||||||
|
// If there is at least one waiting work item then the
|
||||||
|
// method returns immidiately with it.
|
||||||
|
//
|
||||||
|
// If there are no waiting work items then the caller
|
||||||
|
// is queued between other waiters for a work item to arrive.
|
||||||
|
//
|
||||||
|
// If a work item didn't come within millisecondsTimeout or
|
||||||
|
// the user canceled the wait by signaling the cancelEvent
|
||||||
|
// then the method returns null to indicate that the caller
|
||||||
|
// didn't get a work item.
|
||||||
|
|
||||||
|
WaiterEntry waiterEntry;
|
||||||
|
WorkItem workItem = null;
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
ValidateNotDisposed();
|
||||||
|
|
||||||
|
// If there are waiting work items then take one and return.
|
||||||
|
if (_workItems.Count > 0)
|
||||||
|
{
|
||||||
|
workItem = _workItems.Dequeue() as WorkItem;
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No waiting work items ...
|
||||||
|
|
||||||
|
// Get the waiter entry for the waiters queue
|
||||||
|
waiterEntry = GetThreadWaiterEntry();
|
||||||
|
|
||||||
|
// Put the waiter with the other waiters
|
||||||
|
PushWaiter(waiterEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare array of wait handle for the WaitHandle.WaitAny()
|
||||||
|
WaitHandle [] waitHandles = new WaitHandle[] {
|
||||||
|
waiterEntry.WaitHandle,
|
||||||
|
cancelEvent };
|
||||||
|
|
||||||
|
// Wait for an available resource, cancel event, or timeout.
|
||||||
|
|
||||||
|
// During the wait we are supposes to exit the synchronization
|
||||||
|
// domain. (Placing true as the third argument of the WaitAny())
|
||||||
|
// It just doesn't work, I don't know why, so I have two lock(this)
|
||||||
|
// statments instead of one.
|
||||||
|
|
||||||
|
int index = STPEventWaitHandle.WaitAny(
|
||||||
|
waitHandles,
|
||||||
|
millisecondsTimeout,
|
||||||
|
true);
|
||||||
|
|
||||||
|
lock(this)
|
||||||
|
{
|
||||||
|
// success is true if it got a work item.
|
||||||
|
bool success = (0 == index);
|
||||||
|
|
||||||
|
// The timeout variable is used only for readability.
|
||||||
|
// (We treat cancel as timeout)
|
||||||
|
bool timeout = !success;
|
||||||
|
|
||||||
|
// On timeout update the waiterEntry that it is timed out
|
||||||
|
if (timeout)
|
||||||
|
{
|
||||||
|
// The Timeout() fails if the waiter has already been signaled
|
||||||
|
timeout = waiterEntry.Timeout();
|
||||||
|
|
||||||
|
// On timeout remove the waiter from the queue.
|
||||||
|
// Note that the complexity is O(1).
|
||||||
|
if(timeout)
|
||||||
|
{
|
||||||
|
RemoveWaiter(waiterEntry, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Again readability
|
||||||
|
success = !timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On success return the work item
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
workItem = waiterEntry.WorkItem;
|
||||||
|
|
||||||
|
if (null == workItem)
|
||||||
|
{
|
||||||
|
workItem = _workItems.Dequeue() as WorkItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// On failure return null.
|
||||||
|
return workItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cleanup the work items queue, hence no more work
|
||||||
|
/// items are allowed to be queue
|
||||||
|
/// </summary>
|
||||||
|
private void Cleanup()
|
||||||
|
{
|
||||||
|
lock(this)
|
||||||
|
{
|
||||||
|
// Deactivate only once
|
||||||
|
if (!_isWorkItemsQueueActive)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't queue more work items
|
||||||
|
_isWorkItemsQueueActive = false;
|
||||||
|
|
||||||
|
foreach(WorkItem workItem in _workItems)
|
||||||
|
{
|
||||||
|
workItem.DisposeOfState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the work items that are already queued
|
||||||
|
_workItems.Clear();
|
||||||
|
|
||||||
|
// Note:
|
||||||
|
// I don't iterate over the queue and dispose of work items's states,
|
||||||
|
// since if a work item has a state object that is still in use in the
|
||||||
|
// application then I must not dispose it.
|
||||||
|
|
||||||
|
// Tell the waiters that they were timed out.
|
||||||
|
// It won't signal them to exit, but to ignore their
|
||||||
|
// next work item.
|
||||||
|
while(_waitersCount > 0)
|
||||||
|
{
|
||||||
|
WaiterEntry waiterEntry = PopWaiter();
|
||||||
|
waiterEntry.Timeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] GetStates()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
object[] states = new object[_workItems.Count];
|
||||||
|
int i = 0;
|
||||||
|
foreach (WorkItem workItem in _workItems)
|
||||||
|
{
|
||||||
|
states[i] = workItem.GetWorkItemResult().State;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return states;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the WaiterEntry of the current thread
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// In order to avoid creation and destuction of WaiterEntry
|
||||||
|
/// objects each thread has its own WaiterEntry object.
|
||||||
|
private static WaiterEntry GetThreadWaiterEntry()
|
||||||
|
{
|
||||||
|
if (null == CurrentWaiterEntry)
|
||||||
|
{
|
||||||
|
CurrentWaiterEntry = new WaiterEntry();
|
||||||
|
}
|
||||||
|
CurrentWaiterEntry.Reset();
|
||||||
|
return CurrentWaiterEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Waiters stack methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Push a new waiter into the waiter's stack
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newWaiterEntry">A waiter to put in the stack</param>
|
||||||
|
public void PushWaiter(WaiterEntry newWaiterEntry)
|
||||||
|
{
|
||||||
|
// Remove the waiter if it is already in the stack and
|
||||||
|
// update waiter's count as needed
|
||||||
|
RemoveWaiter(newWaiterEntry, false);
|
||||||
|
|
||||||
|
// If the stack is empty then newWaiterEntry is the new head of the stack
|
||||||
|
if (null == _headWaiterEntry._nextWaiterEntry)
|
||||||
|
{
|
||||||
|
_headWaiterEntry._nextWaiterEntry = newWaiterEntry;
|
||||||
|
newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
|
||||||
|
|
||||||
|
}
|
||||||
|
// If the stack is not empty then put newWaiterEntry as the new head
|
||||||
|
// of the stack.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Save the old first waiter entry
|
||||||
|
WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
|
||||||
|
|
||||||
|
// Update the links
|
||||||
|
_headWaiterEntry._nextWaiterEntry = newWaiterEntry;
|
||||||
|
newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
|
||||||
|
newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
|
||||||
|
oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment the number of waiters
|
||||||
|
++_waitersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pop a waiter from the waiter's stack
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns the first waiter in the stack</returns>
|
||||||
|
private WaiterEntry PopWaiter()
|
||||||
|
{
|
||||||
|
// Store the current stack head
|
||||||
|
WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
|
||||||
|
|
||||||
|
// Store the new stack head
|
||||||
|
WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
|
||||||
|
|
||||||
|
// Update the old stack head list links and decrement the number
|
||||||
|
// waiters.
|
||||||
|
RemoveWaiter(oldFirstWaiterEntry, true);
|
||||||
|
|
||||||
|
// Update the new stack head
|
||||||
|
_headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
|
||||||
|
if (null != newHeadWaiterEntry)
|
||||||
|
{
|
||||||
|
newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the old stack head
|
||||||
|
return oldFirstWaiterEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a waiter from the stack
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="waiterEntry">A waiter entry to remove</param>
|
||||||
|
/// <param name="popDecrement">If true the waiter count is always decremented</param>
|
||||||
|
private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
|
||||||
|
{
|
||||||
|
// Store the prev entry in the list
|
||||||
|
WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
|
||||||
|
|
||||||
|
// Store the next entry in the list
|
||||||
|
WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
|
||||||
|
|
||||||
|
// A flag to indicate if we need to decrement the waiters count.
|
||||||
|
// If we got here from PopWaiter then we must decrement.
|
||||||
|
// If we got here from PushWaiter then we decrement only if
|
||||||
|
// the waiter was already in the stack.
|
||||||
|
bool decrementCounter = popDecrement;
|
||||||
|
|
||||||
|
// Null the waiter's entry links
|
||||||
|
waiterEntry._prevWaiterEntry = null;
|
||||||
|
waiterEntry._nextWaiterEntry = null;
|
||||||
|
|
||||||
|
// If the waiter entry had a prev link then update it.
|
||||||
|
// It also means that the waiter is already in the list and we
|
||||||
|
// need to decrement the waiters count.
|
||||||
|
if (null != prevWaiterEntry)
|
||||||
|
{
|
||||||
|
prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
|
||||||
|
decrementCounter = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the waiter entry had a next link then update it.
|
||||||
|
// It also means that the waiter is already in the list and we
|
||||||
|
// need to decrement the waiters count.
|
||||||
|
if (null != nextWaiterEntry)
|
||||||
|
{
|
||||||
|
nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
|
||||||
|
decrementCounter = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrement the waiters count if needed
|
||||||
|
if (decrementCounter)
|
||||||
|
{
|
||||||
|
--_waitersCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region WaiterEntry class
|
||||||
|
|
||||||
|
// A waiter entry in the _waiters queue.
|
||||||
|
public sealed class WaiterEntry : IDisposable
|
||||||
|
{
|
||||||
|
#region Member variables
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event to signal the waiter that it got the work item.
|
||||||
|
/// </summary>
|
||||||
|
//private AutoResetEvent _waitHandle = new AutoResetEvent(false);
|
||||||
|
private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag to know if this waiter already quited from the queue
|
||||||
|
/// because of a timeout.
|
||||||
|
/// </summary>
|
||||||
|
private bool _isTimedout = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag to know if the waiter was signaled and got a work item.
|
||||||
|
/// </summary>
|
||||||
|
private bool _isSignaled = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A work item that passed directly to the waiter withou going
|
||||||
|
/// through the queue
|
||||||
|
/// </summary>
|
||||||
|
private WorkItem _workItem = null;
|
||||||
|
|
||||||
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
|
// Linked list members
|
||||||
|
internal WaiterEntry _nextWaiterEntry = null;
|
||||||
|
internal WaiterEntry _prevWaiterEntry = null;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Construction
|
||||||
|
|
||||||
|
public WaiterEntry()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public methods
|
||||||
|
|
||||||
|
public WaitHandle WaitHandle
|
||||||
|
{
|
||||||
|
get { return _waitHandle; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItem WorkItem
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signal the waiter that it got a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Return true on success</returns>
|
||||||
|
/// The method fails if Timeout() preceded its call
|
||||||
|
public bool Signal(WorkItem workItem)
|
||||||
|
{
|
||||||
|
lock(this)
|
||||||
|
{
|
||||||
|
if (!_isTimedout)
|
||||||
|
{
|
||||||
|
_workItem = workItem;
|
||||||
|
_isSignaled = true;
|
||||||
|
_waitHandle.Set();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mark the wait entry that it has been timed out
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Return true on success</returns>
|
||||||
|
/// The method fails if Signal() preceded its call
|
||||||
|
public bool Timeout()
|
||||||
|
{
|
||||||
|
lock(this)
|
||||||
|
{
|
||||||
|
// Time out can happen only if the waiter wasn't marked as
|
||||||
|
// signaled
|
||||||
|
if (!_isSignaled)
|
||||||
|
{
|
||||||
|
// We don't remove the waiter from the queue, the DequeueWorkItem
|
||||||
|
// method skips _waiters that were timed out.
|
||||||
|
_isTimedout = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reset the wait entry so it can be used again
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_workItem = null;
|
||||||
|
_isTimedout = false;
|
||||||
|
_isSignaled = false;
|
||||||
|
_waitHandle.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Free resources
|
||||||
|
/// </summary>
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
if (null != _waitHandle)
|
||||||
|
{
|
||||||
|
_waitHandle.Close();
|
||||||
|
_waitHandle = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
_isDisposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
_isDisposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateNotDisposed()
|
||||||
|
{
|
||||||
|
if(_isDisposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
23
Networking/Util/HelperMethods.cs
Normal file
23
Networking/Util/HelperMethods.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PortScanner.Util
|
||||||
|
{
|
||||||
|
public static class HelperMethods
|
||||||
|
{
|
||||||
|
public static void PauseForXSeconds(int secondsPaused)
|
||||||
|
{
|
||||||
|
secondsPaused = (int)TimeSpanUtil.ConvertMillisecondsToSeconds(secondsPaused);
|
||||||
|
System.Threading.Thread.Sleep(secondsPaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PauseForXMinutes(int minutesPaused)
|
||||||
|
{
|
||||||
|
minutesPaused = (int)TimeSpanUtil.ConvertMinutesToMilliseconds(minutesPaused);
|
||||||
|
System.Threading.Thread.Sleep(minutesPaused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
131
Networking/Util/TimeSpanUtil.cs
Normal file
131
Networking/Util/TimeSpanUtil.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PortScanner.Util
|
||||||
|
{
|
||||||
|
public static class TimeSpanUtil
|
||||||
|
{
|
||||||
|
#region To days
|
||||||
|
|
||||||
|
public static double ConvertMillisecondsToDays(double milliseconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMilliseconds(milliseconds).TotalDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertSecondsToDays(double seconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromSeconds(seconds).TotalDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertMinutesToDays(double minutes)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMinutes(minutes).TotalDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertHoursToDays(double hours)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromHours(hours).TotalDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion To days
|
||||||
|
|
||||||
|
#region To hours
|
||||||
|
|
||||||
|
public static double ConvertMillisecondsToHours(double milliseconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMilliseconds(milliseconds).TotalHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertSecondsToHours(double seconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromSeconds(seconds).TotalHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertMinutesToHours(double minutes)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMinutes(minutes).TotalHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertDaysToHours(double days)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromHours(days).TotalHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion To hours
|
||||||
|
|
||||||
|
#region To minutes
|
||||||
|
|
||||||
|
public static double ConvertMillisecondsToMinutes(double milliseconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMilliseconds(milliseconds).TotalMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertSecondsToMinutes(double seconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromSeconds(seconds).TotalMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertHoursToMinutes(double hours)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromHours(hours).TotalMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertDaysToMinutes(double days)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromDays(days).TotalMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion To minutes
|
||||||
|
|
||||||
|
#region To seconds
|
||||||
|
|
||||||
|
public static double ConvertMillisecondsToSeconds(double milliseconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMilliseconds(milliseconds).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertMinutesToSeconds(double minutes)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMinutes(minutes).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertHoursToSeconds(double hours)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromHours(hours).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertDaysToSeconds(double days)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromDays(days).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion To seconds
|
||||||
|
|
||||||
|
#region To milliseconds
|
||||||
|
|
||||||
|
public static double ConvertSecondsToMilliseconds(double seconds)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromSeconds(seconds).TotalMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertMinutesToMilliseconds(double minutes)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromMinutes(minutes).TotalMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertHoursToMilliseconds(double hours)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromHours(hours).TotalMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double ConvertDaysToMilliseconds(double days)
|
||||||
|
{
|
||||||
|
return TimeSpan.FromDays(days).TotalMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion To milliseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="PTConverter.Plugin" version="1.0.2" targetFramework="net472" />
|
<package id="PTConverter.Plugin" version="1.0.3" targetFramework="net472" />
|
||||||
</packages>
|
</packages>
|
||||||
6
WpfApp1/App.config
Normal file
6
WpfApp1/App.config
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
9
WpfApp1/App.xaml
Normal file
9
WpfApp1/App.xaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Application x:Class="WpfApp1.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:WpfApp1"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
17
WpfApp1/App.xaml.cs
Normal file
17
WpfApp1/App.xaml.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WpfApp1
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für "App.xaml"
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
15
WpfApp1/MainWindow.xaml
Normal file
15
WpfApp1/MainWindow.xaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<Window
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:WpfApp1"
|
||||||
|
xmlns:Pages="clr-namespace:Networking.Pages;assembly=Networking" x:Class="WpfApp1.MainWindow"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="MainWindow" Height="450" Width="800">
|
||||||
|
<Grid>
|
||||||
|
|
||||||
|
<Pages:PortScanner Margin="0,0,34,10"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
28
WpfApp1/MainWindow.xaml.cs
Normal file
28
WpfApp1/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace WpfApp1
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaktionslogik für MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
WpfApp1/Properties/AssemblyInfo.cs
Normal file
55
WpfApp1/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||||
|
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||||
|
// die einer Assembly zugeordnet sind.
|
||||||
|
[assembly: AssemblyTitle("WpfApp1")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("WpfApp1")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2022")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
|
||||||
|
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
|
||||||
|
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
//Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie
|
||||||
|
//<UICulture>ImCodeVerwendeteKultur</UICulture> in der .csproj-Datei
|
||||||
|
//in einer <PropertyGroup> fest. Wenn Sie in den Quelldateien beispielsweise Deutsch
|
||||||
|
//(Deutschland) verwenden, legen Sie <UICulture> auf \"de-DE\" fest. Heben Sie dann die Auskommentierung
|
||||||
|
//des nachstehenden NeutralResourceLanguage-Attributs auf. Aktualisieren Sie "en-US" in der nachstehenden Zeile,
|
||||||
|
//sodass es mit der UICulture-Einstellung in der Projektdatei übereinstimmt.
|
||||||
|
|
||||||
|
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||||
|
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //Speicherort der designspezifischen Ressourcenwörterbücher
|
||||||
|
//(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird,
|
||||||
|
// oder in den Anwendungsressourcen-Wörterbüchern nicht gefunden werden kann.)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //Speicherort des generischen Ressourcenwörterbuchs
|
||||||
|
//(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird,
|
||||||
|
// designspezifischen Ressourcenwörterbuch nicht gefunden werden kann.)
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||||
|
//
|
||||||
|
// Hauptversion
|
||||||
|
// Nebenversion
|
||||||
|
// Buildnummer
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
|
||||||
|
// indem Sie "*" wie unten gezeigt eingeben:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
70
WpfApp1/Properties/Resources.Designer.cs
generated
Normal file
70
WpfApp1/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// Dieser Code wurde von einem Tool generiert.
|
||||||
|
// Laufzeitversion: 4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn
|
||||||
|
// der Code erneut generiert wird.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace WpfApp1.Properties
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
|
||||||
|
/// </summary>
|
||||||
|
// Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse
|
||||||
|
// über ein Tool wie ResGen oder Visual Studio automatisch generiert.
|
||||||
|
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
|
||||||
|
// mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((resourceMan == null))
|
||||||
|
{
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfApp1.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
|
||||||
|
/// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
117
WpfApp1/Properties/Resources.resx
Normal file
117
WpfApp1/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
29
WpfApp1/Properties/Settings.Designer.cs
generated
Normal file
29
WpfApp1/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace WpfApp1.Properties
|
||||||
|
{
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
WpfApp1/Properties/Settings.settings
Normal file
7
WpfApp1/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
112
WpfApp1/WpfApp1.csproj
Normal file
112
WpfApp1/WpfApp1.csproj
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{89252909-F8E2-4BDB-8EA9-4DA1A329545C}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<RootNamespace>WpfApp1</RootNamespace>
|
||||||
|
<AssemblyName>WpfApp1</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="PTConverter.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\PTConverter.Plugin.1.0.3\lib\net472\PTConverter.Plugin.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xaml">
|
||||||
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UIAutomationProvider" />
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
<Reference Include="WindowsFormsIntegration" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
<Page Include="MainWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="App.xaml.cs">
|
||||||
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Networking\Networking.csproj">
|
||||||
|
<Project>{85d8795c-e9dc-4a59-b669-e2a8eeac7a9e}</Project>
|
||||||
|
<Name>Networking</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
4
WpfApp1/packages.config
Normal file
4
WpfApp1/packages.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="PTConverter.Plugin" version="1.0.3" targetFramework="net48" />
|
||||||
|
</packages>
|
||||||
Reference in New Issue
Block a user