Compare commits

..

4 Commits

Author SHA1 Message Date
14ac62828d -> Bugfix in IPScanner 2022-04-30 21:41:12 +02:00
Kevin Krüger
a07655faed -> PortScanner added 2022-01-18 09:14:22 +01:00
f7b63cb8e1 -> IPScanner implemented 2022-01-17 22:25:15 +01:00
Kevin Krüger
bb6c229875 -> IPScanner added
-> PortScanner added
2022-01-17 15:17:34 +01:00
70 changed files with 10521 additions and 36 deletions

View File

@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31911.196
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Networking", "Networking\Networking.csproj", "{85D8795C-E9DC-4A59-B669-E2A8EEAC7A9E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApp1", "WpfApp1\WpfApp1.csproj", "{89252909-F8E2-4BDB-8EA9-4DA1A329545C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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;
//}
}
}

View 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);
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IPScanner
{
public enum ScanStatus
{
Initializing,
Scanning,
NotFound,
Complete,
Partial
}
}

View File

@@ -37,10 +37,18 @@
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<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 Include="System" />
<Reference Include="System.Configuration" />
<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.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -48,17 +56,87 @@
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="UIAutomationProvider" />
<Reference Include="WindowsBase" />
<Reference Include="WindowsFormsIntegration" />
</ItemGroup>
<ItemGroup>
<Compile Include="IPTool.cs" />
<Compile Include="Networking.IPv4.xaml.cs">
<DependentUpon>Networking.IPv4.xaml</DependentUpon>
<Compile Include="IPScannerLib\HiResTimer.cs" />
<Compile Include="IPScannerLib\HttpHelper.cs" />
<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 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="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>
<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>
<Generator>MSBuild:Compile</Generator>
</Page>
@@ -69,5 +147,13 @@
<ItemGroup>
<None Include="packages.config" />
</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" />
</Project>

View 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>

View 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";
}
}

View File

@@ -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: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"
xmlns:local="clr-namespace:Networking.Pages"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Background="White">
<Grid>
<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="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"/>
<TextBox x:Name="maxCountHosts" HorizontalAlignment="Left" Height="24" Margin="258,236,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"/>
<TextBox x:Name="calcBroadcast" HorizontalAlignment="Left" Height="24" Margin="258,294,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"/>
<TextBox x:Name="clacMaxNetCount" HorizontalAlignment="Left" Height="24" Margin="258,352,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="336"/>
<TextBox x:Name="nextNumOfHosts" HorizontalAlignment="Left" Height="24" Margin="258,381,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="70"/>
<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" TabIndex="5"/>
<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" TabIndex="7"/>
<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" TabIndex="9"/>
<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="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="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"/>
<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="tbIPAddressP3" Text="255" HorizontalAlignment="Left" Height="23" Margin="105,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" />
<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" 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" TabIndex="3" />
<Label Content=".
" 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"/>

View File

@@ -15,37 +15,23 @@ using System.Windows.Shapes;
using NetCalc;
using PTConverter.Plugin;
namespace Networking
namespace Networking.Pages
{
/// <summary>
/// Interaktionslogik für Networking.xaml
/// </summary>
public partial class Networking_IPv4 : UserControl, IPlugin, IPage
public partial class IPv4 : UserControl, IPage
{
#region Declarations
protected IPTool ip = null;
protected bool fill = false; // lock events wenn updating
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
private string _ipAddress = "0.0.0.0";
private string IPAddress { get => tbIPAddressP1.Text + "." + tbIPAddressP2.Text + "." + tbIPAddressP3.Text + "." + tbIPAddressP4.Text; set => _ipAddress = value; }
public Networking_IPv4()
public IPv4()
{
InitializeComponent();
@@ -61,7 +47,7 @@ namespace Networking
}
public string GetCategory() => "Networking";
public string GetUnderCategory() => "IPv4";
public UserControl GetPage() => new Networking_IPv4();
public UserControl GetPage() => new IPv4();
#region Methods Used
protected void newIP()

View 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>

View 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
View 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;
}
}

View 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();
}
}
}

View 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>

View 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;
}
}

View 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;
}
}
}
}

View 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
View 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() }
};
}
}

View 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);
}
}

View 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;
}
}
}

View 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);
}
}

View 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);
}
}
}
}

View 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.
}
}
}

View 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;
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}
}

View 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

View 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; }
}
}

View 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

View 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
}
}

View 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
}

View 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&lt;TResult&gt; 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&lt;TResult&gt; 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&lt;TResult&gt; 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&lt;TResult&gt; 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&lt;TResult&gt; 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&lt;T&gt;
/// </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&lt;TResult&gt; interface.
/// Created when a Func&lt;TResult&gt; 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
}

View 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; }
}
}

View 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
}

View File

@@ -0,0 +1,16 @@
#if _SILVERLIGHT
using System.Threading;
namespace Amib.Threading
{
public enum ThreadPriority
{
Lowest,
BelowNormal,
Normal,
AboveNormal,
Highest,
}
}
#endif

View 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

View 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
}
}
}

View 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
}
}

View 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
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}
}
}

View 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();
}
}
}
}

View 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&lt;...&gt;/Func&lt;...&gt; 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 };
}
}
}

View 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
}
}

View 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;
}
}
}
}
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}
}

View 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
}

View 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);
}
}
}

View 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
}
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="PTConverter.Plugin" version="1.0.2" targetFramework="net472" />
<package id="PTConverter.Plugin" version="1.0.3" targetFramework="net472" />
</packages>

6
WpfApp1/App.config Normal file
View 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
View 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
View 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
View 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>

View 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();
}
}
}

View 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
View 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;
}
}
}
}

View 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
View 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;
}
}
}
}

View 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
View 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
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="PTConverter.Plugin" version="1.0.3" targetFramework="net48" />
</packages>