(nameof(WorkingDirectory), value);
+ }
+ }
+
+ internal override TaskActionType InternalActionType => TaskActionType.Execute;
+
+ /// Determines whether the specified path is a valid filename and, optionally, if it exists.
+ /// The path.
+ /// if set to true check if file exists.
+ /// if set to true throw exception on error.
+ /// true if the specified path is a valid filename; otherwise, false.
+ public static bool IsValidPath(string path, bool checkIfExists = true, bool throwOnException = false)
+ {
+ try
+ {
+ if (path == null) throw new ArgumentNullException(nameof(path));
+ /*if (path.StartsWith("\"") && path.EndsWith("\"") && path.Length > 1)
+ path = path.Substring(1, path.Length - 2);*/
+ var fn = System.IO.Path.GetFileName(path);
+ System.Diagnostics.Debug.WriteLine($"IsValidPath fn={fn}");
+ if (fn == string.Empty)
+ return false;
+ var dn = System.IO.Path.GetDirectoryName(path);
+ System.Diagnostics.Debug.WriteLine($"IsValidPath dir={dn ?? "null"}");
+ System.IO.Path.GetFullPath(path);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"IsValidPath exc={ex}");
+ if (throwOnException) throw;
+ }
+ return false;
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ public override bool Equals(Action other) => base.Equals(other) && Path == ((ExecAction)other).Path && Arguments == ((ExecAction)other).Arguments && WorkingDirectory == ((ExecAction)other).WorkingDirectory;
+
+ ///
+ /// Validates the input as a valid filename and optionally checks for its existence. If valid, the property is
+ /// set to the validated absolute file path.
+ ///
+ /// The file path to validate.
+ /// if set to true check if the file exists.
+ public void SetValidatedPath([NotNull] string path, bool checkIfExists = true)
+ {
+ if (IsValidPath(path, checkIfExists, true))
+ Path = path;
+ }
+
+ /// Gets a string representation of the .
+ /// String representation of this action.
+ public override string ToString() => string.Format(Properties.Resources.ExecAction, Path, Arguments, WorkingDirectory, Id);
+
+ internal static string BuildPowerShellCmd(string actionType, string cmd) => string.Format(PowerShellArgFormat, ScriptIdentifer, actionType, cmd);
+
+ internal static ExecAction ConvertToPowerShellAction(Action action) => CreatePowerShellAction(action.ActionType.ToString(), action.GetPowerShellCommand());
+
+ internal static ExecAction CreatePowerShellAction(string actionType, string cmd) => new ExecAction(PowerShellPath, BuildPowerShellCmd(actionType, cmd));
+
+ internal static Action FromPowerShellCommand(string p)
+ {
+ var match = System.Text.RegularExpressions.Regex.Match(p, "^Start-Process -FilePath '(?[^']*)'(?: -ArgumentList '(?[^']*)')?(?: -WorkingDirectory '(?[^']*)')?;?\\s*$");
+ return match.Success ? new ExecAction(match.Groups["p"].Value, match.Groups["a"].Success ? match.Groups["a"].Value.Replace("''", "'") : null, match.Groups["d"].Success ? match.Groups["d"].Value : null) : null;
+ }
+
+ /// Copies the properties from another the current instance.
+ /// The source .
+ internal override void CopyProperties(Action sourceAction)
+ {
+ if (sourceAction.GetType() == GetType())
+ {
+ base.CopyProperties(sourceAction);
+ Path = ((ExecAction)sourceAction).Path;
+ Arguments = ((ExecAction)sourceAction).Arguments;
+ WorkingDirectory = ((ExecAction)sourceAction).WorkingDirectory;
+ }
+ }
+
+ internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.Execute);
+
+ internal override string GetPowerShellCommand()
+ {
+ var sb = new System.Text.StringBuilder($"Start-Process -FilePath '{Path}'");
+ if (!string.IsNullOrEmpty(Arguments))
+ sb.Append($" -ArgumentList '{Arguments.Replace("'", "''")}'");
+ if (!string.IsNullOrEmpty(WorkingDirectory))
+ sb.Append($" -WorkingDirectory '{WorkingDirectory}'");
+ return sb.Append("; ").ToString();
+ }
+
+ internal string[] ParsePowerShellItems()
+ {
+ if (((Path?.EndsWith(PowerShellPath, StringComparison.InvariantCultureIgnoreCase) ?? false) ||
+ (Path?.EndsWith(PowerShellPath + ".exe", StringComparison.InvariantCultureIgnoreCase) ?? false)) && (Arguments?.Contains(ScriptIdentifer) ?? false))
+ {
+ var match = System.Text.RegularExpressions.Regex.Match(Arguments, @"<# " + ScriptIdentifer + ":(?\\w+) #> (?.+)}\"$");
+ if (match.Success)
+ return new[] { match.Groups["type"].Value, match.Groups["cmd"].Value };
+ }
+ return null;
+ }
+ }
+
+ ///
+ /// Represents an action that shows a message box when a task is activated. Only available for Task Scheduler 2.0 on Windows Vista
+ /// or Windows Server 2003 and later.This action has been deprecated in Windows 8 and later. However, this
+ /// library is able to mimic its functionality using PowerShell if the property is
+ /// set to . To disable this conversion, set the value to .
+ ///
+ /// Display a message when the trigger fires using the ShowMessageAction.
+ ///
+ ///
+ ///
+ ///
+ ///
+ [XmlType(IncludeInSchema = true)]
+ [XmlRoot("ShowMessage", Namespace = TaskDefinition.tns, IsNullable = false)]
+ public sealed class ShowMessageAction : Action, IBindAsExecAction
+ {
+ /// Creates a new unbound instance of .
+ public ShowMessageAction() { }
+
+ /// Creates a new unbound instance of .
+ /// Message text that is displayed in the body of the message box.
+ /// Title of the message box.
+ public ShowMessageAction([CanBeNull] string messageBody, [CanBeNull] string title)
+ {
+ MessageBody = messageBody;
+ Title = title;
+ }
+
+ internal ShowMessageAction([NotNull] V1Interop.ITask task) : base(task)
+ {
+ }
+
+ internal ShowMessageAction([NotNull] IAction action) : base(action)
+ {
+ }
+
+ /// Gets or sets the message text that is displayed in the body of the message box.
+ [XmlElement("Body")]
+ [DefaultValue(null)]
+ public string MessageBody
+ {
+ get => GetProperty(nameof(MessageBody));
+ set => SetProperty(nameof(MessageBody), value);
+ }
+
+ /// Gets or sets the title of the message box.
+ [DefaultValue(null)]
+ public string Title
+ {
+ get => GetProperty(nameof(Title));
+ set => SetProperty(nameof(Title), value);
+ }
+
+ internal override TaskActionType InternalActionType => TaskActionType.ShowMessage;
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ public override bool Equals(Action other) => base.Equals(other) && string.Equals(Title, (other as ShowMessageAction)?.Title) && string.Equals(MessageBody, (other as ShowMessageAction)?.MessageBody);
+
+ /// Gets a string representation of the .
+ /// String representation of this action.
+ public override string ToString() => string.Format(Properties.Resources.ShowMessageAction, Title, MessageBody, Id);
+
+ internal static Action FromPowerShellCommand(string p)
+ {
+ var match = System.Text.RegularExpressions.Regex.Match(p, @"^\[System.Reflection.Assembly\]::LoadWithPartialName\('System.Windows.Forms'\); \[System.Windows.Forms.MessageBox\]::Show\('(?(?:[^']|'')*)'(?:,'(?(?:[^']|'')*)')?\);?\s*$");
+ return match.Success ? new ShowMessageAction(match.Groups["msg"].Value.Replace("''", "'"), match.Groups["t"].Success ? match.Groups["t"].Value.Replace("''", "'") : null) : null;
+ }
+
+ /// Copies the properties from another the current instance.
+ /// The source .
+ internal override void CopyProperties(Action sourceAction)
+ {
+ if (sourceAction.GetType() == GetType())
+ {
+ base.CopyProperties(sourceAction);
+ Title = ((ShowMessageAction)sourceAction).Title;
+ MessageBody = ((ShowMessageAction)sourceAction).MessageBody;
+ }
+ }
+
+ internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.ShowMessage);
+
+ internal override string GetPowerShellCommand()
+ {
+ // [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Your_Desired_Message','Your_Desired_Title');
+ var sb = new System.Text.StringBuilder("[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('");
+ sb.Append(MessageBody.Replace("'", "''"));
+ if (Title != null)
+ {
+ sb.Append("','");
+ sb.Append(Title.Replace("'", "''"));
+ }
+ sb.Append("'); ");
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/FlashPatcher/TaskService/ActionCollection.cs b/FlashPatcher/TaskService/ActionCollection.cs
new file mode 100644
index 0000000..7546db0
--- /dev/null
+++ b/FlashPatcher/TaskService/ActionCollection.cs
@@ -0,0 +1,771 @@
+using JetBrains.Annotations;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Xml.Serialization;
+
+namespace Microsoft.Win32.TaskScheduler
+{
+ /// Options for when to convert actions to PowerShell equivalents.
+ [Flags]
+ public enum PowerShellActionPlatformOption
+ {
+ ///
+ /// Never convert any actions to PowerShell. This will force exceptions to be thrown when unsupported actions our action quantities
+ /// are found.
+ ///
+ Never = 0,
+
+ ///
+ /// Convert actions under Version 1 of the library (Windows XP or Windows Server 2003 and earlier). This option supports multiple
+ /// actions of all types. If not specified, only a single is supported. Developer must ensure that
+ /// PowerShell v2 or higher is installed on the target computer.
+ ///
+ Version1 = 1,
+
+ ///
+ /// Convert all and references to their PowerShell equivalents on systems
+ /// on or after Windows 8 / Server 2012.
+ ///
+ Version2 = 2,
+
+ /// Convert all actions regardless of version or operating system.
+ All = 3
+ }
+
+ /// Collection that contains the actions that are performed by the task.
+ [XmlRoot("Actions", Namespace = TaskDefinition.tns, IsNullable = false)]
+ [PublicAPI]
+ public sealed class ActionCollection : IList, IDisposable, IXmlSerializable, IList, INotifyCollectionChanged, INotifyPropertyChanged
+ {
+ internal const int MaxActions = 32;
+ private const string IndexerName = "Item[]";
+ private static readonly string psV2IdRegex = $"(?:; )?{nameof(PowerShellConversion)}=(?0|1)";
+ private bool inV2set;
+ private PowerShellActionPlatformOption psConvert = PowerShellActionPlatformOption.Version2;
+ private readonly List v1Actions;
+ private V1Interop.ITask v1Task;
+ private readonly V2Interop.IActionCollection v2Coll;
+ private V2Interop.ITaskDefinition v2Def;
+
+ internal ActionCollection([NotNull] V1Interop.ITask task)
+ {
+ v1Task = task;
+ v1Actions = GetV1Actions();
+ PowerShellConversion = Action.TryParse(v1Task.GetDataItem(nameof(PowerShellConversion)), psConvert | PowerShellActionPlatformOption.Version2);
+ }
+
+ internal ActionCollection([NotNull] V2Interop.ITaskDefinition iTaskDef)
+ {
+ v2Def = iTaskDef;
+ v2Coll = iTaskDef.Actions;
+ System.Text.RegularExpressions.Match match;
+ if (iTaskDef.Data != null && (match = System.Text.RegularExpressions.Regex.Match(iTaskDef.Data, psV2IdRegex)).Success)
+ {
+ var on = false;
+ try { on = bool.Parse(match.Groups["v"].Value); } catch { try { on = int.Parse(match.Groups["v"].Value) == 1; } catch { } }
+ if (on)
+ psConvert |= PowerShellActionPlatformOption.Version2;
+ else
+ psConvert &= ~PowerShellActionPlatformOption.Version2;
+ }
+ UnconvertUnsupportedActions();
+ }
+
+ /// Occurs when a collection changes.
+ public event NotifyCollectionChangedEventHandler CollectionChanged;
+
+ /// Occurs when a property value changes.
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ /// Gets or sets the identifier of the principal for the task.
+ [XmlAttribute]
+ [DefaultValue(null)]
+ [CanBeNull]
+ public string Context
+ {
+ get
+ {
+ if (v2Coll != null)
+ return v2Coll.Context;
+ return v1Task.GetDataItem("ActionCollectionContext");
+ }
+ set
+ {
+ if (v2Coll != null)
+ v2Coll.Context = value;
+ else
+ v1Task.SetDataItem("ActionCollectionContext", value);
+ OnNotifyPropertyChanged();
+ }
+ }
+
+ ///
+ /// Gets or sets the systems under which unsupported actions will be converted to PowerShell instances.
+ ///
+ /// The PowerShell platform options.
+ ///
+ /// This property will affect how many actions are physically stored in the system and is tied to the version of Task Scheduler.
+ ///
+ /// If set to , then no actions will ever be converted to PowerShell. This will
+ /// force exceptions to be thrown when unsupported actions our action quantities are found.
+ ///
+ ///
+ /// If set to , then actions will be converted only under Version 1 of the
+ /// library (Windows XP or Windows Server 2003 and earlier). This option supports multiple actions of all types. If not specified,
+ /// only a single is supported. Developer must ensure that PowerShell v2 or higher is installed on the
+ /// target computer.
+ ///
+ ///
+ /// If set to (which is the default value), then and references will be converted to their PowerShell equivalents on systems
+ /// on or after Windows 8 / Server 2012.
+ ///
+ ///
+ /// If set to , then any actions not supported by the Task Scheduler version will be
+ /// converted to PowerShell.
+ ///
+ ///
+ [DefaultValue(typeof(PowerShellActionPlatformOption), "Version2")]
+ public PowerShellActionPlatformOption PowerShellConversion
+ {
+ get => psConvert;
+ set
+ {
+ if (psConvert != value)
+ {
+ psConvert = value;
+ if (v1Task != null)
+ v1Task.SetDataItem(nameof(PowerShellConversion), value.ToString());
+ if (v2Def != null)
+ {
+ if (!string.IsNullOrEmpty(v2Def.Data))
+ v2Def.Data = System.Text.RegularExpressions.Regex.Replace(v2Def.Data, psV2IdRegex, "");
+ if (!SupportV2Conversion)
+ v2Def.Data = string.Format("{0}; {1}=0", v2Def.Data, nameof(PowerShellConversion));
+ }
+ OnNotifyPropertyChanged();
+ }
+ }
+ }
+
+ /// Gets or sets an XML-formatted version of the collection.
+ public string XmlText
+ {
+ get
+ {
+ if (v2Coll != null)
+ return v2Coll.XmlText;
+ return XmlSerializationHelper.WriteObjectToXmlText(this);
+ }
+ set
+ {
+ if (v2Coll != null)
+ v2Coll.XmlText = value;
+ else
+ XmlSerializationHelper.ReadObjectFromXmlText(value, this);
+ OnNotifyPropertyChanged();
+ }
+ }
+
+ /// Gets the number of actions in the collection.
+ public int Count => (v2Coll != null) ? v2Coll.Count : v1Actions.Count;
+
+ bool IList.IsFixedSize => false;
+ bool ICollection.IsReadOnly => false;
+ bool IList.IsReadOnly => false;
+ bool ICollection.IsSynchronized => false;
+
+ object ICollection.SyncRoot => this;
+ private bool SupportV1Conversion => (PowerShellConversion & PowerShellActionPlatformOption.Version1) != 0;
+
+ private bool SupportV2Conversion => (PowerShellConversion & PowerShellActionPlatformOption.Version2) != 0;
+
+ /// Gets or sets a specified action from the collection.
+ /// The .
+ /// The id ( ) of the action to be retrieved.
+ /// Specialized instance.
+ ///
+ ///
+ ///
+ /// Mismatching Id for action and lookup.
+ [NotNull]
+ public Action this[string actionId]
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(actionId))
+ throw new ArgumentNullException(nameof(actionId));
+ var t = Find(a => string.Equals(a.Id, actionId));
+ if (t != null)
+ return t;
+ throw new ArgumentOutOfRangeException(nameof(actionId));
+ }
+ set
+ {
+ if (value == null)
+ throw new NullReferenceException();
+ if (string.IsNullOrEmpty(actionId))
+ throw new ArgumentNullException(nameof(actionId));
+ var index = IndexOf(actionId);
+ value.Id = actionId;
+ if (index >= 0)
+ this[index] = value;
+ else
+ Add(value);
+ }
+ }
+
+ /// Gets or sets a an action at the specified index.
+ /// The zero-based index of the action to get or set.
+ [NotNull]
+ public Action this[int index]
+ {
+ get
+ {
+ if (v2Coll != null)
+ return Action.CreateAction(v2Coll[++index]);
+ if (v1Task != null)
+ {
+ if (SupportV1Conversion)
+ return v1Actions[index];
+ else
+ {
+ if (index == 0)
+ return v1Actions[0];
+ }
+ }
+ throw new ArgumentOutOfRangeException();
+ }
+ set
+ {
+ if (index < 0 || Count <= index)
+ throw new ArgumentOutOfRangeException(nameof(index), index, "Index is not a valid index in the ActionCollection");
+ var orig = this[index].Clone();
+ if (v2Coll != null)
+ {
+ inV2set = true;
+ try
+ {
+ Insert(index, value);
+ RemoveAt(index + 1);
+ }
+ finally
+ {
+ inV2set = false;
+ }
+ }
+ else
+ {
+ v1Actions[index] = value;
+ SaveV1Actions();
+ }
+ OnNotifyPropertyChanged(IndexerName);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, orig, index));
+ }
+ }
+
+ object IList.this[int index]
+ {
+ get => this[index];
+ set => this[index] = (Action)value;
+ }
+
+ /// Adds an action to the task.
+ /// A type derived from .
+ /// A derived class.
+ /// The bound that was added to the collection.
+ [NotNull]
+ public TAction Add([NotNull] TAction action) where TAction : Action
+ {
+ if (action == null)
+ throw new ArgumentNullException(nameof(action));
+ if (v2Def != null)
+ action.Bind(v2Def);
+ else
+ {
+ if (!SupportV1Conversion && (v1Actions.Count >= 1 || !(action is ExecAction)))
+ throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value.");
+ v1Actions.Add(action);
+ SaveV1Actions();
+ }
+ OnNotifyPropertyChanged(nameof(Count));
+ OnNotifyPropertyChanged(IndexerName);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, action));
+ return action;
+ }
+
+ /// Adds an to the task.
+ /// Path to an executable file.
+ /// Arguments associated with the command-line operation. This value can be null.
+ ///
+ /// Directory that contains either the executable file or the files that are used by the executable file. This value can be null.
+ ///
+ /// The bound that was added to the collection.
+ [NotNull]
+ public ExecAction Add([NotNull] string path, [CanBeNull] string arguments = null, [CanBeNull] string workingDirectory = null) =>
+ Add(new ExecAction(path, arguments, workingDirectory));
+
+ /// Adds a new instance to the task.
+ /// Type of task to be created
+ /// Specialized instance.
+ [NotNull]
+ public Action AddNew(TaskActionType actionType)
+ {
+ if (Count >= MaxActions)
+ throw new ArgumentOutOfRangeException(nameof(actionType), "A maximum of 32 actions is allowed within a single task.");
+ if (v1Task != null)
+ {
+ if (!SupportV1Conversion && (v1Actions.Count >= 1 || actionType != TaskActionType.Execute))
+ throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value.");
+ return Action.CreateAction(v1Task);
+ }
+ return Action.CreateAction(v2Coll.Create(actionType));
+ }
+
+ /// Adds a collection of actions to the end of the .
+ ///
+ /// The actions to be added to the end of the . The collection itself cannot be null and cannot
+ /// contain null elements.
+ ///
+ /// is null.
+ public void AddRange([ItemNotNull, NotNull] IEnumerable actions)
+ {
+ if (actions == null)
+ throw new ArgumentNullException(nameof(actions));
+ if (v1Task != null)
+ {
+ var list = new List(actions);
+ var at = list.Count == 1 && list[0].ActionType == TaskActionType.Execute;
+ if (!SupportV1Conversion && ((v1Actions.Count + list.Count) > 1 || !at))
+ throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value.");
+ v1Actions.AddRange(actions);
+ SaveV1Actions();
+ }
+ else
+ {
+ foreach (var item in actions)
+ Add(item);
+ }
+ }
+
+ /// Clears all actions from the task.
+ public void Clear()
+ {
+ if (v2Coll != null)
+ v2Coll.Clear();
+ else
+ {
+ v1Actions.Clear();
+ SaveV1Actions();
+ }
+ OnNotifyPropertyChanged(nameof(Count));
+ OnNotifyPropertyChanged(IndexerName);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ }
+
+ /// Determines whether the contains a specific value.
+ /// The object to locate in the .
+ /// true if is found in the ; otherwise, false.
+ public bool Contains([NotNull] Action item) => Find(a => a.Equals(item)) != null;
+
+ /// Determines whether the specified action type is contained in this collection.
+ /// Type of the action.
+ /// true if the specified action type is contained in this collection; otherwise, false.
+ public bool ContainsType(Type actionType) => Find(a => a.GetType() == actionType) != null;
+
+ ///
+ /// Copies the elements of the to an array of , starting at a particular index.
+ ///
+ ///
+ /// The array that is the destination of the elements copied from . The array must have zero-based indexing.
+ ///
+ /// The zero-based index in array at which copying begins.
+ public void CopyTo(Action[] array, int arrayIndex) => CopyTo(0, array, arrayIndex, Count);
+
+ ///
+ /// Copies the elements of the to an array, starting at a particular array index.
+ ///
+ /// The zero-based index in the source at which copying begins.
+ ///
+ /// The array that is the destination of the elements copied from . The array must have zero-based indexing.
+ ///
+ /// The zero-based index in array at which copying begins.
+ /// The number of elements to copy.
+ /// is null.
+ /// is less than 0.
+ ///
+ /// The number of elements in the source is greater than the available space from to the end of the destination .
+ ///
+ public void CopyTo(int index, [NotNull] Action[] array, int arrayIndex, int count)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex));
+ if (count < 0 || count > (Count - index))
+ throw new ArgumentOutOfRangeException(nameof(count));
+ if ((Count - index) > (array.Length - arrayIndex))
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex));
+ for (var i = 0; i < count; i++)
+ array[arrayIndex + i] = (Action)this[index + i].Clone();
+ }
+
+ /// Releases all resources used by this class.
+ public void Dispose()
+ {
+ v1Task = null;
+ v2Def = null;
+ if (v2Coll != null) Marshal.ReleaseComObject(v2Coll);
+ }
+
+ ///
+ /// Searches for an that matches the conditions defined by the specified predicate, and returns the first
+ /// occurrence within the entire collection.
+ ///
+ ///
+ /// The delegate that defines the conditions of the to search for.
+ ///
+ ///
+ /// The first that matches the conditions defined by the specified predicate, if found; otherwise, null.
+ ///
+ public Action Find(Predicate match)
+ {
+ if (match == null)
+ throw new ArgumentNullException(nameof(match));
+ foreach (var item in this)
+ if (match(item)) return item;
+ return null;
+ }
+
+ ///
+ /// Searches for an that matches the conditions defined by the specified predicate, and returns the zero-based
+ /// index of the first occurrence within the collection that starts at the specified index and contains the specified number of elements.
+ ///
+ /// The zero-based starting index of the search.
+ /// The number of elements in the collection to search.
+ /// The delegate that defines the conditions of the element to search for.
+ ///
+ /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.
+ ///
+ public int FindIndexOf(int startIndex, int count, [NotNull] Predicate match)
+ {
+ if (startIndex < 0 || startIndex >= Count)
+ throw new ArgumentOutOfRangeException(nameof(startIndex));
+ if (startIndex + count > Count)
+ throw new ArgumentOutOfRangeException(nameof(count));
+ if (match == null)
+ throw new ArgumentNullException(nameof(match));
+ for (var i = startIndex; i < startIndex + count; i++)
+ if (match(this[i])) return i;
+ return -1;
+ }
+
+ ///
+ /// Searches for an that matches the conditions defined by the specified predicate, and returns the zero-based
+ /// index of the first occurrence within the collection.
+ ///
+ /// The delegate that defines the conditions of the element to search for.
+ ///
+ /// The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.
+ ///
+ public int FindIndexOf([NotNull] Predicate match) => FindIndexOf(0, Count, match);
+
+ /// Retrieves an enumeration of each of the actions.
+ ///
+ /// Returns an object that implements the interface and that can iterate through the
+ /// objects within the .
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ if (v2Coll != null)
+ return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], Action.CreateAction);
+ return v1Actions.GetEnumerator();
+ }
+
+ /// Determines the index of a specific item in the .
+ /// The object to locate in the .
+ /// The index of if found in the list; otherwise, -1.
+ public int IndexOf(Action item) => FindIndexOf(a => a.Equals(item));
+
+ /// Determines the index of a specific item in the .
+ /// The id ( ) of the action to be retrieved.
+ /// The index of if found in the list; otherwise, -1.
+ public int IndexOf(string actionId)
+ {
+ if (string.IsNullOrEmpty(actionId))
+ throw new ArgumentNullException(nameof(actionId));
+ return FindIndexOf(a => string.Equals(a.Id, actionId));
+ }
+
+ /// Inserts an action at the specified index.
+ /// The zero-based index at which action should be inserted.
+ /// The action to insert into the list.
+ public void Insert(int index, [NotNull] Action action)
+ {
+ if (action == null)
+ throw new ArgumentNullException(nameof(action));
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ if (v2Coll != null)
+ {
+ var pushItems = new Action[Count - index];
+ if (Count != index)
+ {
+ CopyTo(index, pushItems, 0, Count - index);
+ for (var j = Count - 1; j >= index; j--)
+ RemoveAt(j);
+ }
+ Add(action);
+ if (Count != index)
+ for (var k = 0; k < pushItems.Length; k++)
+ Add(pushItems[k]);
+ }
+ else
+ {
+ if (!SupportV1Conversion && (index > 0 || !(action is ExecAction)))
+ throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value.");
+ v1Actions.Insert(index, action);
+ SaveV1Actions();
+ }
+
+ if (!inV2set)
+ {
+ OnNotifyPropertyChanged(nameof(Count));
+ OnNotifyPropertyChanged(IndexerName);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, action, index));
+ }
+ }
+
+ /// Removes the first occurrence of a specific object from the .
+ /// The object to remove from the .
+ ///
+ /// true if was successfully removed from the ; otherwise, false. This method
+ /// also returns false if is not found in the original .
+ ///
+ public bool Remove([NotNull] Action item)
+ {
+ var idx = IndexOf(item);
+ if (idx != -1)
+ {
+ try
+ {
+ RemoveAt(idx);
+ return true;
+ }
+ catch { }
+ }
+ return false;
+ }
+
+ /// Removes the action at a specified index.
+ /// Index of action to remove.
+ /// Index out of range.
+ public void RemoveAt(int index)
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index), index, "Failed to remove action. Index out of range.");
+ var item = this[index].Clone();
+ if (v2Coll != null)
+ v2Coll.Remove(++index);
+ else
+ {
+ v1Actions.RemoveAt(index);
+ SaveV1Actions();
+ }
+ if (!inV2set)
+ {
+ OnNotifyPropertyChanged(nameof(Count));
+ OnNotifyPropertyChanged(IndexerName);
+ CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
+ }
+ }
+
+ /// Copies the elements of the to a new array.
+ /// An array containing copies of the elements of the .
+ [NotNull, ItemNotNull]
+ public Action[] ToArray()
+ {
+ var ret = new Action[Count];
+ CopyTo(ret, 0);
+ return ret;
+ }
+
+ /// Returns a that represents the actions in this collection.
+ /// A that represents the actions in this collection.
+ public override string ToString()
+ {
+ if (Count == 1)
+ return this[0].ToString();
+ if (Count > 1)
+ return Properties.Resources.MultipleActions;
+ return string.Empty;
+ }
+
+ void ICollection.Add(Action item) => Add(item);
+
+ int IList.Add(object value)
+ {
+ Add((Action)value);
+ return Count - 1;
+ }
+
+ bool IList.Contains(object value) => Contains((Action)value);
+
+ void ICollection.CopyTo(Array array, int index)
+ {
+ if (array != null && array.Rank != 1)
+ throw new RankException("Multi-dimensional arrays are not supported.");
+ var src = new Action[Count];
+ CopyTo(src, 0);
+ Array.Copy(src, 0, array, index, Count);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null;
+
+ int IList.IndexOf(object value) => IndexOf((Action)value);
+
+ void IList.Insert(int index, object value) => Insert(index, (Action)value);
+
+ void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
+ {
+ reader.ReadStartElement(XmlSerializationHelper.GetElementName(this), TaskDefinition.tns);
+ Context = reader.GetAttribute("Context");
+ while (reader.MoveToContent() == System.Xml.XmlNodeType.Element)
+ {
+ var a = Action.CreateAction(Action.TryParse(reader.LocalName == "Exec" ? "Execute" : reader.LocalName, TaskActionType.Execute));
+ XmlSerializationHelper.ReadObject(reader, a);
+ Add(a);
+ }
+ reader.ReadEndElement();
+ }
+
+ void IList.Remove(object value) => Remove((Action)value);
+
+ void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
+ {
+ // TODO:FIX if (!string.IsNullOrEmpty(Context)) writer.WriteAttributeString("Context", Context);
+ foreach (var item in this)
+ XmlSerializationHelper.WriteObject(writer, item);
+ }
+
+ internal void ConvertUnsupportedActions()
+ {
+ if (TaskService.LibraryVersion.Minor > 3 && SupportV2Conversion)
+ {
+ for (var i = 0; i < Count; i++)
+ {
+ var action = this[i];
+ var bindable = action as IBindAsExecAction;
+ if (bindable != null && !(action is ComHandlerAction))
+ this[i] = ExecAction.ConvertToPowerShellAction(action);
+ }
+ }
+ }
+
+ private List GetV1Actions()
+ {
+ var ret = new List();
+ if (v1Task != null && v1Task.GetDataItem("ActionType") != "EMPTY")
+ {
+ var exec = new ExecAction(v1Task);
+ var items = exec.ParsePowerShellItems();
+ if (items != null)
+ {
+ if (items.Length == 2 && items[0] == "MULTIPLE")
+ {
+ PowerShellConversion |= PowerShellActionPlatformOption.Version1;
+ var mc = System.Text.RegularExpressions.Regex.Matches(items[1], @"<# (?\w+):(?\w+) #>\s*(?[^<#]*)\s*");
+ foreach (System.Text.RegularExpressions.Match ms in mc)
+ {
+ var a = Action.ActionFromScript(ms.Groups["t"].Value, ms.Groups["c"].Value);
+ if (a != null)
+ {
+ if (ms.Groups["id"].Value != "NO_ID")
+ a.Id = ms.Groups["id"].Value;
+ ret.Add(a);
+ }
+ }
+ }
+ else
+ ret.Add(ExecAction.ConvertFromPowerShellAction(exec));
+ }
+ else if (!string.IsNullOrEmpty(exec.Path))
+ {
+ ret.Add(exec);
+ }
+ }
+ return ret;
+ }
+
+ /// Called when a property has changed to notify any attached elements.
+ /// Name of the property.
+ private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+
+ private void SaveV1Actions()
+ {
+ if (v1Task == null)
+ throw new ArgumentNullException(nameof(v1Task));
+ if (v1Actions.Count == 0)
+ {
+ v1Task.SetApplicationName(string.Empty);
+ v1Task.SetParameters(string.Empty);
+ v1Task.SetWorkingDirectory(string.Empty);
+ v1Task.SetDataItem("ActionId", null);
+ v1Task.SetDataItem("ActionType", "EMPTY");
+ }
+ else if (v1Actions.Count == 1)
+ {
+ if (!SupportV1Conversion && v1Actions[0].ActionType != TaskActionType.Execute)
+ throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value.");
+ v1Task.SetDataItem("ActionType", null);
+ v1Actions[0].Bind(v1Task);
+ }
+ else
+ {
+ if (!SupportV1Conversion)
+ throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value.");
+ // Build list of internal PowerShell scripts
+ var sb = new System.Text.StringBuilder();
+ foreach (var item in v1Actions)
+ sb.Append($"<# {item.Id ?? "NO_ID"}:{item.ActionType} #> {item.GetPowerShellCommand()} ");
+
+ // Build and save PS ExecAction
+ var ea = ExecAction.CreatePowerShellAction("MULTIPLE", sb.ToString());
+ ea.Bind(v1Task);
+ v1Task.SetDataItem("ActionId", null);
+ v1Task.SetDataItem("ActionType", "MULTIPLE");
+ }
+ }
+
+ private void UnconvertUnsupportedActions()
+ {
+ if (TaskService.LibraryVersion.Minor > 3)
+ {
+ for (var i = 0; i < Count; i++)
+ {
+ var action = this[i] as ExecAction;
+ if (action != null)
+ {
+ var newAction = Action.ConvertFromPowerShellAction(action);
+ if (newAction != null)
+ this[i] = newAction;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/FlashPatcher/TaskService/CultureSwitcher.cs b/FlashPatcher/TaskService/CultureSwitcher.cs
new file mode 100644
index 0000000..f4d1b7f
--- /dev/null
+++ b/FlashPatcher/TaskService/CultureSwitcher.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Threading;
+
+namespace Microsoft.Win32.TaskScheduler
+{
+ internal class CultureSwitcher : IDisposable
+ {
+ private readonly System.Globalization.CultureInfo cur, curUI;
+
+ public CultureSwitcher([JetBrains.Annotations.NotNull] System.Globalization.CultureInfo culture)
+ {
+ cur = Thread.CurrentThread.CurrentCulture;
+ curUI = Thread.CurrentThread.CurrentUICulture;
+ Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = culture;
+ }
+
+ public void Dispose()
+ {
+ Thread.CurrentThread.CurrentCulture = cur;
+ Thread.CurrentThread.CurrentUICulture = curUI;
+ }
+ }
+}
diff --git a/FlashPatcher/TaskService/EnumGlobalizer.cs b/FlashPatcher/TaskService/EnumGlobalizer.cs
new file mode 100644
index 0000000..b636406
--- /dev/null
+++ b/FlashPatcher/TaskService/EnumGlobalizer.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace Microsoft.Win32.TaskScheduler
+{
+ ///
+ /// Functions to provide localized strings for enumerated types and values.
+ ///
+ public static class TaskEnumGlobalizer
+ {
+ ///
+ /// Gets a string representing the localized value of the provided enum.
+ ///
+ /// The enum value.
+ /// A localized string, if available.
+ public static string GetString(object enumValue)
+ {
+ switch (enumValue.GetType().Name)
+ {
+ case "DaysOfTheWeek":
+ return GetCultureEquivalentString((DaysOfTheWeek)enumValue);
+ case "MonthsOfTheYear":
+ return GetCultureEquivalentString((MonthsOfTheYear)enumValue);
+ case "TaskTriggerType":
+ return BuildEnumString("TriggerType", enumValue);
+ case "WhichWeek":
+ return BuildEnumString("WW", enumValue);
+ case "TaskActionType":
+ return BuildEnumString("ActionType", enumValue);
+ case "TaskState":
+ return BuildEnumString("TaskState", enumValue);
+ }
+ return enumValue.ToString();
+ }
+
+ private static string GetCultureEquivalentString(DaysOfTheWeek val)
+ {
+ if (val == DaysOfTheWeek.AllDays)
+ return Properties.Resources.DOWAllDays;
+
+ var s = new List(7);
+ var vals = Enum.GetValues(val.GetType());
+ for (var i = 0; i < vals.Length - 1; i++)
+ {
+ if ((val & (DaysOfTheWeek)vals.GetValue(i)) > 0)
+ s.Add(DateTimeFormatInfo.CurrentInfo.GetDayName((DayOfWeek)i));
+ }
+
+ return string.Join(Properties.Resources.ListSeparator, s.ToArray());
+ }
+
+ private static string GetCultureEquivalentString(MonthsOfTheYear val)
+ {
+ if (val == MonthsOfTheYear.AllMonths)
+ return Properties.Resources.MOYAllMonths;
+
+ var s = new List(12);
+ var vals = Enum.GetValues(val.GetType());
+ for (var i = 0; i < vals.Length - 1; i++)
+ {
+ if ((val & (MonthsOfTheYear)vals.GetValue(i)) > 0)
+ s.Add(DateTimeFormatInfo.CurrentInfo.GetMonthName(i+1));
+ }
+
+ return string.Join(Properties.Resources.ListSeparator, s.ToArray());
+ }
+
+ private static string BuildEnumString(string preface, object enumValue)
+ {
+ var vals = enumValue.ToString().Split(new[] { ", " }, StringSplitOptions.None);
+ if (vals.Length == 0)
+ return string.Empty;
+ for (var i = 0; i < vals.Length; i++)
+ vals[i] = Properties.Resources.ResourceManager.GetString(preface + vals[i]);
+ return string.Join(Properties.Resources.ListSeparator, vals);
+ }
+ }
+}
diff --git a/FlashPatcher/TaskService/JetBrains.Annotations.cs b/FlashPatcher/TaskService/JetBrains.Annotations.cs
new file mode 100644
index 0000000..0c68ef1
--- /dev/null
+++ b/FlashPatcher/TaskService/JetBrains.Annotations.cs
@@ -0,0 +1,1065 @@
+/* MIT License
+
+Copyright (c) 2016 JetBrains http://www.jetbrains.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. */
+
+using System;
+
+#pragma warning disable 1591
+// ReSharper disable UnusedMember.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable IntroduceOptionalParameters.Global
+// ReSharper disable MemberCanBeProtected.Global
+// ReSharper disable InconsistentNaming
+
+namespace JetBrains.Annotations
+{
+ ///
+ /// Indicates that the value of the marked element could be null sometimes,
+ /// so the check for null is necessary before its usage.
+ ///
+ ///
+ /// [CanBeNull] object Test() => null;
+ ///
+ /// void UseTest() {
+ /// var p = Test();
+ /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException'
+ /// }
+ ///
+ [AttributeUsage(
+ AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
+ AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event |
+ AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)]
+ internal sealed class CanBeNullAttribute : Attribute { }
+
+ ///
+ /// Indicates that the value of the marked element could never be null.
+ ///
+ ///
+ /// [NotNull] object Foo() {
+ /// return null; // Warning: Possible 'null' assignment
+ /// }
+ ///
+ [AttributeUsage(
+ AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
+ AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event |
+ AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)]
+ internal sealed class NotNullAttribute : Attribute { }
+
+ ///
+ /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task
+ /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property
+ /// or of the Lazy.Value property can never be null.
+ ///
+ [AttributeUsage(
+ AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
+ AttributeTargets.Delegate | AttributeTargets.Field)]
+ internal sealed class ItemNotNullAttribute : Attribute { }
+
+ ///
+ /// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task
+ /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property
+ /// or of the Lazy.Value property can be null.
+ ///
+ [AttributeUsage(
+ AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property |
+ AttributeTargets.Delegate | AttributeTargets.Field)]
+ internal sealed class ItemCanBeNullAttribute : Attribute { }
+
+ ///
+ /// Indicates that the marked method builds string by format pattern and (optional) arguments.
+ /// Parameter, which contains format string, should be given in constructor. The format string
+ /// should be in -like form.
+ ///
+ ///
+ /// [StringFormatMethod("message")]
+ /// void ShowError(string message, params object[] args) { /* do something */ }
+ ///
+ /// void Foo() {
+ /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string
+ /// }
+ ///
+ [AttributeUsage(
+ AttributeTargets.Constructor | AttributeTargets.Method |
+ AttributeTargets.Property | AttributeTargets.Delegate)]
+ internal sealed class StringFormatMethodAttribute : Attribute
+ {
+ ///
+ /// Specifies which parameter of an annotated method should be treated as format-string
+ ///
+ public StringFormatMethodAttribute([NotNull] string formatParameterName)
+ {
+ FormatParameterName = formatParameterName;
+ }
+
+ [NotNull] public string FormatParameterName { get; private set; }
+ }
+
+ ///
+ /// For a parameter that is expected to be one of the limited set of values.
+ /// Specify fields of which type should be used as values for this parameter.
+ ///
+ [AttributeUsage(
+ AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field,
+ AllowMultiple = true)]
+ internal sealed class ValueProviderAttribute : Attribute
+ {
+ public ValueProviderAttribute([NotNull] string name)
+ {
+ Name = name;
+ }
+
+ [NotNull] public string Name { get; private set; }
+ }
+
+ ///
+ /// Indicates that the function argument should be string literal and match one
+ /// of the parameters of the caller function. For example, ReSharper annotates
+ /// the parameter of .
+ ///
+ ///
+ /// void Foo(string param) {
+ /// if (param == null)
+ /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol
+ /// }
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class InvokerParameterNameAttribute : Attribute { }
+
+ ///
+ /// Indicates that the method is contained in a type that implements
+ /// System.ComponentModel.INotifyPropertyChanged interface and this method
+ /// is used to notify that some property value changed.
+ ///
+ ///
+ /// The method should be non-static and conform to one of the supported signatures:
+ ///
+ /// - NotifyChanged(string)
+ /// - NotifyChanged(params string[])
+ /// - NotifyChanged{T}(Expression{Func{T}})
+ /// - NotifyChanged{T,U}(Expression{Func{T,U}})
+ /// - SetProperty{T}(ref T, T, string)
+ ///
+ ///
+ ///
+ /// public class Foo : INotifyPropertyChanged {
+ /// public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ /// [NotifyPropertyChangedInvocator]
+ /// protected virtual void NotifyChanged(string propertyName) { ... }
+ ///
+ /// string _name;
+ ///
+ /// public string Name {
+ /// get { return _name; }
+ /// set { _name = value; NotifyChanged("LastName"); /* Warning */ }
+ /// }
+ /// }
+ ///
+ /// Examples of generated notifications:
+ ///
+ /// - NotifyChanged("Property")
+ /// - NotifyChanged(() => Property)
+ /// - NotifyChanged((VM x) => x.Property)
+ /// - SetProperty(ref myField, value, "Property")
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
+ {
+ public NotifyPropertyChangedInvocatorAttribute() { }
+ public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName)
+ {
+ ParameterName = parameterName;
+ }
+
+ [CanBeNull] public string ParameterName { get; private set; }
+ }
+
+ ///
+ /// Describes dependency between method input and output.
+ ///
+ ///
+ /// Function Definition Table syntax:
+ ///
+ /// - FDT ::= FDTRow [;FDTRow]*
+ /// - FDTRow ::= Input => Output | Output <= Input
+ /// - Input ::= ParameterName: Value [, Input]*
+ /// - Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value}
+ /// - Value ::= true | false | null | notnull | canbenull
+ ///
+ /// If method has single input parameter, it's name could be omitted.
+ /// Using halt (or void/nothing, which is the same) for method output
+ /// means that the methos doesn't return normally (throws or terminates the process).
+ /// Value canbenull is only applicable for output parameters.
+ /// You can use multiple [ContractAnnotation] for each FDT row, or use single attribute
+ /// with rows separated by semicolon. There is no notion of order rows, all rows are checked
+ /// for applicability and applied per each program state tracked by R# analysis.
+ ///
+ ///
+ ///
+ /// [ContractAnnotation("=> halt")]
+ /// public void TerminationMethod()
+ ///
+ ///
+ /// [ContractAnnotation("halt <= condition: false")]
+ /// public void Assert(bool condition, string text) // regular assertion method
+ ///
+ ///
+ /// [ContractAnnotation("s:null => true")]
+ /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty()
+ ///
+ ///
+ /// // A method that returns null if the parameter is null,
+ /// // and not null if the parameter is not null
+ /// [ContractAnnotation("null => null; notnull => notnull")]
+ /// public object Transform(object data)
+ ///
+ ///
+ /// [ContractAnnotation("=> true, result: notnull; => false, result: null")]
+ /// public bool TryParse(string s, out Person result)
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+ internal sealed class ContractAnnotationAttribute : Attribute
+ {
+ public ContractAnnotationAttribute([NotNull] string contract)
+ : this(contract, false) { }
+
+ public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates)
+ {
+ Contract = contract;
+ ForceFullStates = forceFullStates;
+ }
+
+ [NotNull] public string Contract { get; private set; }
+
+ public bool ForceFullStates { get; private set; }
+ }
+
+ ///
+ /// Indicates that marked element should be localized or not.
+ ///
+ ///
+ /// [LocalizationRequiredAttribute(true)]
+ /// class Foo {
+ /// string str = "my string"; // Warning: Localizable string
+ /// }
+ ///
+ [AttributeUsage(AttributeTargets.All)]
+ internal sealed class LocalizationRequiredAttribute : Attribute
+ {
+ public LocalizationRequiredAttribute() : this(true) { }
+
+ public LocalizationRequiredAttribute(bool required)
+ {
+ Required = required;
+ }
+
+ public bool Required { get; private set; }
+ }
+
+ ///
+ /// Indicates that the value of the marked type (or its derivatives)
+ /// cannot be compared using '==' or '!=' operators and Equals()
+ /// should be used instead. However, using '==' or '!=' for comparison
+ /// with null is always permitted.
+ ///
+ ///
+ /// [CannotApplyEqualityOperator]
+ /// class NoEquality { }
+ ///
+ /// class UsesNoEquality {
+ /// void Test() {
+ /// var ca1 = new NoEquality();
+ /// var ca2 = new NoEquality();
+ /// if (ca1 != null) { // OK
+ /// bool condition = ca1 == ca2; // Warning
+ /// }
+ /// }
+ /// }
+ ///
+ [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct)]
+ internal sealed class CannotApplyEqualityOperatorAttribute : Attribute { }
+
+ ///
+ /// When applied to a target attribute, specifies a requirement for any type marked
+ /// with the target attribute to implement or inherit specific type or types.
+ ///
+ ///
+ /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement
+ /// class ComponentAttribute : Attribute { }
+ ///
+ /// [Component] // ComponentAttribute requires implementing IComponent interface
+ /// class MyComponent : IComponent { }
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ [BaseTypeRequired(typeof(Attribute))]
+ internal sealed class BaseTypeRequiredAttribute : Attribute
+ {
+ public BaseTypeRequiredAttribute([NotNull] Type baseType)
+ {
+ BaseType = baseType;
+ }
+
+ [NotNull] public Type BaseType { get; private set; }
+ }
+
+ ///
+ /// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library),
+ /// so this symbol will not be marked as unused (as well as by other usage inspections).
+ ///
+ [AttributeUsage(AttributeTargets.All)]
+ internal sealed class UsedImplicitlyAttribute : Attribute
+ {
+ public UsedImplicitlyAttribute()
+ : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { }
+
+ public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
+ : this(useKindFlags, ImplicitUseTargetFlags.Default) { }
+
+ public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
+ : this(ImplicitUseKindFlags.Default, targetFlags) { }
+
+ public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
+ {
+ UseKindFlags = useKindFlags;
+ TargetFlags = targetFlags;
+ }
+
+ public ImplicitUseKindFlags UseKindFlags { get; private set; }
+
+ public ImplicitUseTargetFlags TargetFlags { get; private set; }
+ }
+
+ ///
+ /// Should be used on attributes and causes ReSharper to not mark symbols marked with such attributes
+ /// as unused (as well as by other usage inspections)
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter)]
+ internal sealed class MeansImplicitUseAttribute : Attribute
+ {
+ public MeansImplicitUseAttribute()
+ : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { }
+
+ public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags)
+ : this(useKindFlags, ImplicitUseTargetFlags.Default) { }
+
+ public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags)
+ : this(ImplicitUseKindFlags.Default, targetFlags) { }
+
+ public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
+ {
+ UseKindFlags = useKindFlags;
+ TargetFlags = targetFlags;
+ }
+
+ [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; }
+
+ [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; }
+ }
+
+ [Flags]
+ internal enum ImplicitUseKindFlags
+ {
+ Default = Access | Assign | InstantiatedWithFixedConstructorSignature,
+ /// Only entity marked with attribute considered used.
+ Access = 1,
+ /// Indicates implicit assignment to a member.
+ Assign = 2,
+ ///
+ /// Indicates implicit instantiation of a type with fixed constructor signature.
+ /// That means any unused constructor parameters won't be reported as such.
+ ///
+ InstantiatedWithFixedConstructorSignature = 4,
+ /// Indicates implicit instantiation of a type.
+ InstantiatedNoFixedConstructorSignature = 8,
+ }
+
+ ///
+ /// Specify what is considered used implicitly when marked
+ /// with or .
+ ///
+ [Flags]
+ internal enum ImplicitUseTargetFlags
+ {
+ Default = Itself,
+ Itself = 1,
+ /// Members of entity marked with attribute are considered used.
+ Members = 2,
+ /// Entity marked with attribute and all its members considered used.
+ WithMembers = Itself | Members
+ }
+
+ ///
+ /// This attribute is intended to mark publicly available API
+ /// which should not be removed and so is treated as used.
+ ///
+ [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)]
+ internal sealed class PublicAPIAttribute : Attribute
+ {
+ public PublicAPIAttribute() { }
+
+ public PublicAPIAttribute([NotNull] string comment)
+ {
+ Comment = comment;
+ }
+
+ [CanBeNull] public string Comment { get; private set; }
+ }
+
+ ///
+ /// Tells code analysis engine if the parameter is completely handled when the invoked method is on stack.
+ /// If the parameter is a delegate, indicates that delegate is executed while the method is executed.
+ /// If the parameter is an enumerable, indicates that it is enumerated while the method is executed.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class InstantHandleAttribute : Attribute { }
+
+ ///
+ /// Indicates that a method does not make any observable state changes.
+ /// The same as System.Diagnostics.Contracts.PureAttribute.
+ ///
+ ///
+ /// [Pure] int Multiply(int x, int y) => x * y;
+ ///
+ /// void M() {
+ /// Multiply(123, 42); // Waring: Return value of pure method is not used
+ /// }
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class PureAttribute : Attribute { }
+
+ ///
+ /// Indicates that the return value of method invocation must be used.
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class MustUseReturnValueAttribute : Attribute
+ {
+ public MustUseReturnValueAttribute() { }
+
+ public MustUseReturnValueAttribute([NotNull] string justification)
+ {
+ Justification = justification;
+ }
+
+ [CanBeNull] public string Justification { get; private set; }
+ }
+
+ ///
+ /// Indicates the type member or parameter of some type, that should be used instead of all other ways
+ /// to get the value that type. This annotation is useful when you have some "context" value evaluated
+ /// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one.
+ ///
+ ///
+ /// class Foo {
+ /// [ProvidesContext] IBarService _barService = ...;
+ ///
+ /// void ProcessNode(INode node) {
+ /// DoSomething(node, node.GetGlobalServices().Bar);
+ /// // ^ Warning: use value of '_barService' field
+ /// }
+ /// }
+ ///
+ [AttributeUsage(
+ AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method |
+ AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.GenericParameter)]
+ internal sealed class ProvidesContextAttribute : Attribute { }
+
+ ///
+ /// Indicates that a parameter is a path to a file or a folder within a web project.
+ /// Path can be relative or absolute, starting from web root (~).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class PathReferenceAttribute : Attribute
+ {
+ public PathReferenceAttribute() { }
+
+ public PathReferenceAttribute([NotNull, PathReference] string basePath)
+ {
+ BasePath = basePath;
+ }
+
+ [CanBeNull] public string BasePath { get; private set; }
+ }
+
+ ///
+ /// An extension method marked with this attribute is processed by ReSharper code completion
+ /// as a 'Source Template'. When extension method is completed over some expression, it's source code
+ /// is automatically expanded like a template at call site.
+ ///
+ ///
+ /// Template method body can contain valid source code and/or special comments starting with '$'.
+ /// Text inside these comments is added as source code when the template is applied. Template parameters
+ /// can be used either as additional method parameters or as identifiers wrapped in two '$' signs.
+ /// Use the attribute to specify macros for parameters.
+ ///
+ ///
+ /// In this example, the 'forEach' method is a source template available over all values
+ /// of enumerable types, producing ordinary C# 'foreach' statement and placing caret inside block:
+ ///
+ /// [SourceTemplate]
+ /// public static void forEach<T>(this IEnumerable<T> xs) {
+ /// foreach (var x in xs) {
+ /// //$ $END$
+ /// }
+ /// }
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class SourceTemplateAttribute : Attribute { }
+
+ ///
+ /// Allows specifying a macro for a parameter of a source template.
+ ///
+ ///
+ /// You can apply the attribute on the whole method or on any of its additional parameters. The macro expression
+ /// is defined in the property. When applied on a method, the target
+ /// template parameter is defined in the property. To apply the macro silently
+ /// for the parameter, set the property value = -1.
+ ///
+ ///
+ /// Applying the attribute on a source template method:
+ ///
+ /// [SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")]
+ /// public static void forEach<T>(this IEnumerable<T> collection) {
+ /// foreach (var item in collection) {
+ /// //$ $END$
+ /// }
+ /// }
+ ///
+ /// Applying the attribute on a template method parameter:
+ ///
+ /// [SourceTemplate]
+ /// public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid) {
+ /// /*$ var $x$Id = "$newguid$" + x.ToString();
+ /// x.DoSomething($x$Id); */
+ /// }
+ ///
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = true)]
+ internal sealed class MacroAttribute : Attribute
+ {
+ ///
+ /// Allows specifying a macro that will be executed for a source template
+ /// parameter when the template is expanded.
+ ///
+ [CanBeNull] public string Expression { get; set; }
+
+ ///
+ /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed.
+ ///
+ ///
+ /// If the target parameter is used several times in the template, only one occurrence becomes editable;
+ /// other occurrences are changed synchronously. To specify the zero-based index of the editable occurrence,
+ /// use values >= 0. To make the parameter non-editable when the template is expanded, use -1.
+ /// >
+ public int Editable { get; set; }
+
+ ///
+ /// Identifies the target parameter of a source template if the
+ /// is applied on a template method.
+ ///
+ [CanBeNull] public string Target { get; set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ internal sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute
+ {
+ public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format)
+ {
+ Format = format;
+ }
+
+ [NotNull] public string Format { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ internal sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute
+ {
+ public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format)
+ {
+ Format = format;
+ }
+
+ [NotNull] public string Format { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ internal sealed class AspMvcAreaViewLocationFormatAttribute : Attribute
+ {
+ public AspMvcAreaViewLocationFormatAttribute([NotNull] string format)
+ {
+ Format = format;
+ }
+
+ [NotNull] public string Format { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ internal sealed class AspMvcMasterLocationFormatAttribute : Attribute
+ {
+ public AspMvcMasterLocationFormatAttribute([NotNull] string format)
+ {
+ Format = format;
+ }
+
+ [NotNull] public string Format { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ internal sealed class AspMvcPartialViewLocationFormatAttribute : Attribute
+ {
+ public AspMvcPartialViewLocationFormatAttribute([NotNull] string format)
+ {
+ Format = format;
+ }
+
+ [NotNull] public string Format { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ internal sealed class AspMvcViewLocationFormatAttribute : Attribute
+ {
+ public AspMvcViewLocationFormatAttribute([NotNull] string format)
+ {
+ Format = format;
+ }
+
+ [NotNull] public string Format { get; private set; }
+ }
+
+ ///
+ /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
+ /// is an MVC action. If applied to a method, the MVC action name is calculated
+ /// implicitly from the context. Use this attribute for custom wrappers similar to
+ /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
+ internal sealed class AspMvcActionAttribute : Attribute
+ {
+ public AspMvcActionAttribute() { }
+
+ public AspMvcActionAttribute([NotNull] string anonymousProperty)
+ {
+ AnonymousProperty = anonymousProperty;
+ }
+
+ [CanBeNull] public string AnonymousProperty { get; private set; }
+ }
+
+ ///
+ /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area.
+ /// Use this attribute for custom wrappers similar to
+ /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AspMvcAreaAttribute : Attribute
+ {
+ public AspMvcAreaAttribute() { }
+
+ public AspMvcAreaAttribute([NotNull] string anonymousProperty)
+ {
+ AnonymousProperty = anonymousProperty;
+ }
+
+ [CanBeNull] public string AnonymousProperty { get; private set; }
+ }
+
+ ///
+ /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is
+ /// an MVC controller. If applied to a method, the MVC controller name is calculated
+ /// implicitly from the context. Use this attribute for custom wrappers similar to
+ /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
+ internal sealed class AspMvcControllerAttribute : Attribute
+ {
+ public AspMvcControllerAttribute() { }
+
+ public AspMvcControllerAttribute([NotNull] string anonymousProperty)
+ {
+ AnonymousProperty = anonymousProperty;
+ }
+
+ [CanBeNull] public string AnonymousProperty { get; private set; }
+ }
+
+ ///
+ /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. Use this attribute
+ /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AspMvcMasterAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. Use this attribute
+ /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, Object).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AspMvcModelTypeAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is an MVC
+ /// partial view. If applied to a method, the MVC partial view name is calculated implicitly
+ /// from the context. Use this attribute for custom wrappers similar to
+ /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
+ internal sealed class AspMvcPartialViewAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+ internal sealed class AspMvcSuppressViewErrorAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template.
+ /// Use this attribute for custom wrappers similar to
+ /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AspMvcDisplayTemplateAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template.
+ /// Use this attribute for custom wrappers similar to
+ /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AspMvcEditorTemplateAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template.
+ /// Use this attribute for custom wrappers similar to
+ /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AspMvcTemplateAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
+ /// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly
+ /// from the context. Use this attribute for custom wrappers similar to
+ /// System.Web.Mvc.Controller.View(Object).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
+ internal sealed class AspMvcViewAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
+ /// is an MVC view component name.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AspMvcViewComponentAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
+ /// is an MVC view component view. If applied to a method, the MVC view component view name is default.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
+ internal sealed class AspMvcViewComponentViewAttribute : Attribute { }
+
+ ///
+ /// ASP.NET MVC attribute. When applied to a parameter of an attribute,
+ /// indicates that this parameter is an MVC action name.
+ ///
+ ///
+ /// [ActionName("Foo")]
+ /// public ActionResult Login(string returnUrl) {
+ /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK
+ /// return RedirectToAction("Bar"); // Error: Cannot resolve action
+ /// }
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
+ internal sealed class AspMvcActionSelectorAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)]
+ internal sealed class HtmlElementAttributesAttribute : Attribute
+ {
+ public HtmlElementAttributesAttribute() { }
+
+ public HtmlElementAttributesAttribute([NotNull] string name)
+ {
+ Name = name;
+ }
+
+ [CanBeNull] public string Name { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)]
+ internal sealed class HtmlAttributeValueAttribute : Attribute
+ {
+ public HtmlAttributeValueAttribute([NotNull] string name)
+ {
+ Name = name;
+ }
+
+ [NotNull] public string Name { get; private set; }
+ }
+
+ ///
+ /// Razor attribute. Indicates that a parameter or a method is a Razor section.
+ /// Use this attribute for custom wrappers similar to
+ /// System.Web.WebPages.WebPageBase.RenderSection(String).
+ ///
+ [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
+ internal sealed class RazorSectionAttribute : Attribute { }
+
+ ///
+ /// Indicates how method, constructor invocation or property access
+ /// over collection type affects content of the collection.
+ ///
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)]
+ internal sealed class CollectionAccessAttribute : Attribute
+ {
+ public CollectionAccessAttribute(CollectionAccessType collectionAccessType)
+ {
+ CollectionAccessType = collectionAccessType;
+ }
+
+ public CollectionAccessType CollectionAccessType { get; private set; }
+ }
+
+ [Flags]
+ internal enum CollectionAccessType
+ {
+ /// Method does not use or modify content of the collection.
+ None = 0,
+ /// Method only reads content of the collection but does not modify it.
+ Read = 1,
+ /// Method can change content of the collection but does not add new elements.
+ ModifyExistingContent = 2,
+ /// Method can add new elements to the collection.
+ UpdatedContent = ModifyExistingContent | 4
+ }
+
+ ///
+ /// Indicates that the marked method is assertion method, i.e. it halts control flow if
+ /// one of the conditions is satisfied. To set the condition, mark one of the parameters with
+ /// attribute.
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class AssertionMethodAttribute : Attribute { }
+
+ ///
+ /// Indicates the condition parameter of the assertion method. The method itself should be
+ /// marked by attribute. The mandatory argument of
+ /// the attribute is the assertion type.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class AssertionConditionAttribute : Attribute
+ {
+ public AssertionConditionAttribute(AssertionConditionType conditionType)
+ {
+ ConditionType = conditionType;
+ }
+
+ public AssertionConditionType ConditionType { get; private set; }
+ }
+
+ ///
+ /// Specifies assertion type. If the assertion method argument satisfies the condition,
+ /// then the execution continues. Otherwise, execution is assumed to be halted.
+ ///
+ internal enum AssertionConditionType
+ {
+ /// Marked parameter should be evaluated to true.
+ IS_TRUE = 0,
+ /// Marked parameter should be evaluated to false.
+ IS_FALSE = 1,
+ /// Marked parameter should be evaluated to null value.
+ IS_NULL = 2,
+ /// Marked parameter should be evaluated to not null value.
+ IS_NOT_NULL = 3,
+ }
+
+ ///
+ /// Indicates that the marked method unconditionally terminates control flow execution.
+ /// For example, it could unconditionally throw exception.
+ ///
+ [Obsolete("Use [ContractAnnotation('=> halt')] instead")]
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class TerminatesProgramAttribute : Attribute { }
+
+ ///
+ /// Indicates that method is pure LINQ method, with postponed enumeration (like Enumerable.Select,
+ /// .Where). This annotation allows inference of [InstantHandle] annotation for parameters
+ /// of delegate type by analyzing LINQ method chains.
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class LinqTunnelAttribute : Attribute { }
+
+ ///
+ /// Indicates that IEnumerable, passed as parameter, is not enumerated.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class NoEnumerationAttribute : Attribute { }
+
+ ///
+ /// Indicates that parameter is regular expression pattern.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class RegexPatternAttribute : Attribute { }
+
+ ///
+ /// Prevents the Member Reordering feature from tossing members of the marked class.
+ ///
+ ///
+ /// The attribute must be mentioned in your member reordering patterns
+ ///
+ [AttributeUsage(
+ AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)]
+ internal sealed class NoReorderAttribute : Attribute { }
+
+ ///
+ /// XAML attribute. Indicates the type that has ItemsSource property and should be treated
+ /// as ItemsControl-derived type, to enable inner items DataContext type resolve.
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ internal sealed class XamlItemsControlAttribute : Attribute { }
+
+ ///
+ /// XAML attribute. Indicates the property of some BindingBase-derived type, that
+ /// is used to bind some item of ItemsControl-derived type. This annotation will
+ /// enable the DataContext type resolve for XAML bindings for such properties.
+ ///
+ ///
+ /// Property should have the tree ancestor of the ItemsControl type or
+ /// marked with the attribute.
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ internal sealed class XamlItemBindingOfItemsControlAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ internal sealed class AspChildControlTypeAttribute : Attribute
+ {
+ public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType)
+ {
+ TagName = tagName;
+ ControlType = controlType;
+ }
+
+ [NotNull] public string TagName { get; private set; }
+
+ [NotNull] public Type ControlType { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
+ internal sealed class AspDataFieldAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
+ internal sealed class AspDataFieldsAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Property)]
+ internal sealed class AspMethodPropertyAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ internal sealed class AspRequiredAttributeAttribute : Attribute
+ {
+ public AspRequiredAttributeAttribute([NotNull] string attribute)
+ {
+ Attribute = attribute;
+ }
+
+ [NotNull] public string Attribute { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Property)]
+ internal sealed class AspTypePropertyAttribute : Attribute
+ {
+ public bool CreateConstructorReferences { get; private set; }
+
+ public AspTypePropertyAttribute(bool createConstructorReferences)
+ {
+ CreateConstructorReferences = createConstructorReferences;
+ }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ internal sealed class RazorImportNamespaceAttribute : Attribute
+ {
+ public RazorImportNamespaceAttribute([NotNull] string name)
+ {
+ Name = name;
+ }
+
+ [NotNull] public string Name { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ internal sealed class RazorInjectionAttribute : Attribute
+ {
+ public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName)
+ {
+ Type = type;
+ FieldName = fieldName;
+ }
+
+ [NotNull] public string Type { get; private set; }
+
+ [NotNull] public string FieldName { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ internal sealed class RazorDirectiveAttribute : Attribute
+ {
+ public RazorDirectiveAttribute([NotNull] string directive)
+ {
+ Directive = directive;
+ }
+
+ [NotNull] public string Directive { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ internal sealed class RazorPageBaseTypeAttribute : Attribute
+ {
+ public RazorPageBaseTypeAttribute([NotNull] string baseType)
+ {
+ BaseType = baseType;
+ }
+ public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName)
+ {
+ BaseType = baseType;
+ PageName = pageName;
+ }
+
+ [NotNull] public string BaseType { get; private set; }
+ [CanBeNull] public string PageName { get; private set; }
+ }
+
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class RazorHelperCommonAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Property)]
+ internal sealed class RazorLayoutAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class RazorWriteLiteralMethodAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class RazorWriteMethodAttribute : Attribute { }
+
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class RazorWriteMethodParameterAttribute : Attribute { }
+}
\ No newline at end of file
diff --git a/FlashPatcher/TaskService/NamedValueCollection.cs b/FlashPatcher/TaskService/NamedValueCollection.cs
new file mode 100644
index 0000000..50e195e
--- /dev/null
+++ b/FlashPatcher/TaskService/NamedValueCollection.cs
@@ -0,0 +1,616 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Xml.Serialization;
+using Microsoft.Win32.TaskScheduler.V2Interop;
+using JetBrains.Annotations;
+
+namespace Microsoft.Win32.TaskScheduler
+{
+ ///
+ /// Pair of name and value.
+ ///
+ [PublicAPI]
+ public class NameValuePair : IXmlSerializable, INotifyPropertyChanged, ICloneable, IEquatable, IEquatable
+ {
+ private readonly ITaskNamedValuePair v2Pair;
+ private string name, value;
+
+ ///
+ /// Occurs when a property has changed.
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public NameValuePair() { }
+
+ internal NameValuePair([NotNull] ITaskNamedValuePair iPair)
+ {
+ v2Pair = iPair;
+ }
+
+ internal NameValuePair([NotNull] string name, [NotNull] string value)
+ {
+ if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value))
+ throw new ArgumentException("Both name and value must be non-empty strings.");
+ this.name = name; this.value = value;
+ }
+
+ [XmlIgnore]
+ internal bool AttributedXmlFormat { get; set; } = true;
+
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ [NotNull]
+ public string Name
+ {
+ get { return v2Pair == null ? name : v2Pair.Name; }
+ set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(Name)); if (v2Pair == null) name = value; else v2Pair.Name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name))); }
+ }
+
+ ///
+ /// Gets or sets the value.
+ ///
+ ///
+ /// The value.
+ ///
+ [NotNull]
+ public string Value
+ {
+ get { return v2Pair == null ? value : v2Pair.Value; }
+ set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(Value)); if (v2Pair == null) this.value = value; else v2Pair.Value = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value))); }
+ }
+
+ ///
+ /// Clones this instance.
+ ///
+ /// A copy of an unbound .
+ [NotNull]
+ public NameValuePair Clone() => new NameValuePair(Name, Value);
+
+ object ICloneable.Clone() => Clone();
+
+ ///
+ /// Determines whether the specified , is equal to this instance.
+ ///
+ /// The to compare with this instance.
+ ///
+ /// true if the specified is equal to this instance; otherwise, false.
+ ///
+ public override bool Equals(object obj)
+ {
+ var valuePair = obj as ITaskNamedValuePair;
+ if (valuePair != null)
+ return (this as IEquatable).Equals(valuePair);
+ var pair = obj as NameValuePair;
+ if (pair != null)
+ return Equals(pair);
+ return base.Equals(obj);
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ public bool Equals([NotNull] NameValuePair other) => other.Name == Name && other.Value == Value;
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ bool IEquatable.Equals(ITaskNamedValuePair other) => other.Name == Name && other.Value == Value;
+
+ ///
+ /// Returns a hash code for this instance.
+ ///
+ ///
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
+ ///
+ public override int GetHashCode() => new { A = Name, B = Value }.GetHashCode();
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ ///
+ /// A that represents this instance.
+ ///
+ public override string ToString() => $"{Name}={Value}";
+
+ ///
+ /// Implements the operator implicit NameValuePair.
+ ///
+ /// The KeyValuePair.
+ ///
+ /// The result of the operator.
+ ///
+ public static implicit operator NameValuePair(KeyValuePair kvp) => new NameValuePair(kvp.Key, kvp.Value);
+
+ System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() => null;
+
+ void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
+ {
+ if (reader.MoveToContent() == System.Xml.XmlNodeType.Element && reader.LocalName == "Value")
+ {
+ Name = reader.GetAttribute("name");
+ Value = reader.ReadString();
+ reader.Read();
+ }
+ else
+ {
+ reader.ReadStartElement();
+ XmlSerializationHelper.ReadObjectProperties(reader, this);
+ reader.ReadEndElement();
+ }
+ }
+
+ void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
+ {
+ if (AttributedXmlFormat)
+ {
+ writer.WriteAttributeString("name", Name);
+ writer.WriteString(Value);
+ }
+ else
+ {
+ XmlSerializationHelper.WriteObjectProperties(writer, this);
+ }
+ }
+ }
+
+ ///
+ /// Contains a collection of name-value pairs.
+ ///
+ [PublicAPI]
+ public sealed class NamedValueCollection : IDisposable, ICollection, IDictionary, INotifyCollectionChanged, INotifyPropertyChanged
+ {
+ private ITaskNamedValueCollection v2Coll;
+ private readonly List unboundDict;
+
+ ///
+ /// Occurs when the collection has changed.
+ ///
+ public event NotifyCollectionChangedEventHandler CollectionChanged;
+
+ ///
+ /// Occurs when a property has changed.
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ internal NamedValueCollection([NotNull] ITaskNamedValueCollection iColl) { v2Coll = iColl; }
+
+ internal NamedValueCollection()
+ {
+ unboundDict = new List(5);
+ }
+
+ [XmlIgnore]
+ internal bool AttributedXmlFormat { get; set; } = true;
+
+ internal void Bind([NotNull] ITaskNamedValueCollection iTaskNamedValueCollection)
+ {
+ v2Coll = iTaskNamedValueCollection;
+ v2Coll.Clear();
+ foreach (var item in unboundDict)
+ v2Coll.Create(item.Name, item.Value);
+ }
+
+ ///
+ /// Copies current to another.
+ ///
+ /// The destination collection.
+ public void CopyTo([NotNull] NamedValueCollection destCollection)
+ {
+ if (v2Coll != null)
+ {
+ for (var i = 1; i <= Count; i++)
+ destCollection.Add(v2Coll[i].Name, v2Coll[i].Value);
+ }
+ else
+ {
+ foreach (var item in unboundDict)
+ destCollection.Add(item.Name, item.Value);
+ }
+ }
+
+ ///
+ /// Releases all resources used by this class.
+ ///
+ public void Dispose()
+ {
+ if (v2Coll != null) Marshal.ReleaseComObject(v2Coll);
+ }
+
+ ///
+ /// Gets the number of items in the collection.
+ ///
+ public int Count => v2Coll?.Count ?? unboundDict.Count;
+
+ ///
+ /// Gets a collection of the names.
+ ///
+ ///
+ /// The names.
+ ///
+ [ItemNotNull, NotNull]
+ public ICollection Names
+ {
+ get
+ {
+ if (v2Coll == null)
+ return unboundDict.ConvertAll(p => p.Name);
+
+ var ret = new List(v2Coll.Count);
+ foreach (var item in this)
+ ret.Add(item.Name);
+ return ret;
+ }
+ }
+
+ ///
+ /// Gets a collection of the values.
+ ///
+ ///
+ /// The values.
+ ///
+ [ItemNotNull, NotNull]
+ public ICollection Values
+ {
+ get
+ {
+ if (v2Coll == null)
+ return unboundDict.ConvertAll(p => p.Value);
+
+ var ret = new List(v2Coll.Count);
+ foreach (var item in this)
+ ret.Add(item.Value);
+ return ret;
+ }
+ }
+
+ ///
+ /// Gets the value of the item at the specified index.
+ ///
+ /// The index of the item being requested.
+ /// The value of the name-value pair at the specified index.
+ [NotNull]
+ public string this[int index]
+ {
+ get
+ {
+ if (v2Coll != null)
+ return v2Coll[++index].Value;
+ return unboundDict[index].Value;
+ }
+ }
+
+ ///
+ /// Gets the value of the item with the specified name.
+ ///
+ /// Name to get the value for.
+ /// Value for the name, or null if not found.
+ public string this[string name]
+ {
+ [CanBeNull]
+ get
+ {
+ string ret;
+ TryGetValue(name, out ret);
+ return ret;
+ }
+ [NotNull]
+ set
+ {
+ int idx;
+ NameValuePair old = null;
+ var nvp = new NameValuePair(name, value);
+ if (v2Coll == null)
+ {
+ idx = unboundDict.FindIndex(p => p.Name == name);
+ if (idx == -1)
+ unboundDict.Add(nvp);
+ else
+ {
+ old = unboundDict[idx];
+ unboundDict[idx] = nvp;
+ }
+ }
+ else
+ {
+ var array = new KeyValuePair[Count];
+ ((ICollection>)this).CopyTo(array, 0);
+ idx = Array.FindIndex(array, p => p.Key == name);
+ if (idx == -1)
+ v2Coll.Create(name, value);
+ else
+ {
+ old = array[idx];
+ array[idx] = new KeyValuePair(name, value);
+ v2Coll.Clear();
+ foreach (KeyValuePair t in array)
+ v2Coll.Create(t.Key, t.Value);
+ }
+ }
+ if (idx == -1)
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, nvp));
+ else
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, nvp, old, idx));
+ }
+ }
+
+ ///
+ /// Adds an item to the .
+ ///
+ /// The object to add to the .
+ public void Add([NotNull] NameValuePair item)
+ {
+ if (v2Coll != null)
+ v2Coll.Create(item.Name, item.Value);
+ else
+ unboundDict.Add(item);
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
+ }
+
+ ///
+ /// Adds a name-value pair to the collection.
+ ///
+ /// The name associated with a value in a name-value pair.
+ /// The value associated with a name in a name-value pair.
+ public void Add([NotNull] string name, [NotNull] string value)
+ {
+ Add(new NameValuePair(name, value));
+ }
+
+ ///
+ /// Adds the elements of the specified collection to the end of .
+ ///
+ /// The collection of whose elements should be added to the end of .
+ public void AddRange([ItemNotNull, NotNull] IEnumerable items)
+ {
+ if (v2Coll != null)
+ {
+ foreach (var item in items)
+ v2Coll.Create(item.Name, item.Value);
+ }
+ else
+ unboundDict.AddRange(items);
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items));
+ }
+
+ ///
+ /// Clears the entire collection of name-value pairs.
+ ///
+ public void Clear()
+ {
+ if (v2Coll != null)
+ v2Coll.Clear();
+ else
+ unboundDict.Clear();
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+ }
+
+ ///
+ /// Returns an enumerator that iterates through the collection.
+ ///
+ ///
+ /// A that can be used to iterate through the collection.
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ if (v2Coll == null)
+ return unboundDict.GetEnumerator();
+
+ return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], o => new NameValuePair(o));
+ }
+
+ private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
+ {
+ if (e.NewItems != null)
+ foreach (NameValuePair item in e.NewItems)
+ item.AttributedXmlFormat = AttributedXmlFormat;
+ CollectionChanged?.Invoke(this, e);
+ }
+
+ ///
+ /// Removes the name-value pair with the specified key from the collection.
+ ///
+ /// The name associated with a value in a name-value pair.
+ /// true if item successfully removed; false otherwise.
+ public bool Remove([NotNull] string name)
+ {
+ var i = -1;
+ NameValuePair nvp = null;
+ try
+ {
+ if (v2Coll == null)
+ {
+ i = unboundDict.FindIndex(p => p.Name == name);
+ if (i != -1)
+ {
+ nvp = unboundDict[i];
+ unboundDict.RemoveAt(i);
+ }
+ return (i != -1);
+ }
+
+ for (i = 0; i < v2Coll.Count; i++)
+ {
+ if (name == v2Coll[i].Name)
+ {
+ nvp = new NameValuePair(v2Coll[i]).Clone();
+ v2Coll.Remove(i);
+ return true;
+ }
+ }
+ i = -1;
+ }
+ finally
+ {
+ if (i != -1)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, nvp, i));
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Removes a selected name-value pair from the collection.
+ ///
+ /// Index of the pair to remove.
+ public void RemoveAt(int index)
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ NameValuePair nvp;
+ if (v2Coll != null)
+ {
+ nvp = new NameValuePair(v2Coll[index]).Clone();
+ v2Coll.Remove(index);
+ }
+ else
+ {
+ nvp = unboundDict[index];
+ unboundDict.RemoveAt(index);
+ }
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, nvp, index));
+ }
+
+ ///
+ /// Gets the value associated with the specified name.
+ ///
+ /// The name whose value to get.
+ /// When this method returns, the value associated with the specified name, if the name is found; otherwise, null. This parameter is passed uninitialized.
+ /// true if the collection contains an element with the specified name; otherwise, false.
+ public bool TryGetValue(string name, out string value)
+ {
+ if (v2Coll != null)
+ {
+ foreach (var item in this)
+ {
+ if (string.CompareOrdinal(item.Name, name) == 0)
+ {
+ value = item.Value;
+ return true;
+ }
+ }
+ value = null;
+ return false;
+ }
+
+ var nvp = unboundDict.Find(p => p.Name == name);
+ value = nvp?.Value;
+ return nvp != null;
+ }
+
+ ///
+ /// Gets the collection enumerator for the name-value collection.
+ ///
+ /// An for the collection.
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
+
+ bool ICollection.Contains(NameValuePair item)
+ {
+ if (v2Coll == null)
+ return unboundDict.Contains(item);
+
+ foreach (var invp in this)
+ if (Equals(item, invp)) return true;
+ return false;
+ }
+
+ void ICollection.CopyTo(NameValuePair[] array, int arrayIndex)
+ {
+ if (v2Coll == null)
+ unboundDict.CopyTo(array, arrayIndex);
+ else
+ {
+ if (array.Length - arrayIndex < v2Coll.Count)
+ throw new ArgumentException("Items in collection exceed available items in destination array.");
+ if (arrayIndex < 0)
+ throw new ArgumentException(@"Array index must be 0 or greater.", nameof(arrayIndex));
+ for (var i = 0; i < v2Coll.Count; i++)
+ array[i + arrayIndex] = new NameValuePair(v2Coll[i]);
+ }
+ }
+
+ bool ICollection.IsReadOnly => false;
+
+ ICollection IDictionary.Keys => Names;
+
+ bool ICollection>.IsReadOnly => false;
+
+ bool ICollection.Remove(NameValuePair item)
+ {
+ var i = -1;
+ try
+ {
+ if (v2Coll == null)
+ {
+ if ((i = unboundDict.IndexOf(item)) != -1)
+ return unboundDict.Remove(item);
+ }
+ else
+ {
+ for (i = 0; i < v2Coll.Count; i++)
+ {
+ if (item.Equals(v2Coll[i]))
+ {
+ v2Coll.Remove(i);
+ return true;
+ }
+ }
+ }
+ i = -1;
+ }
+ finally
+ {
+ if (i != -1)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Count)));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, i));
+ }
+ }
+ return false;
+ }
+
+ bool IDictionary.ContainsKey(string key) => Names.Contains(key);
+
+ void ICollection>.Add(KeyValuePair item)
+ {
+ Add(item.Key, item.Value);
+ }
+
+ bool ICollection>.Contains(KeyValuePair item) =>
+ ((ICollection)this).Contains(new NameValuePair(item.Key, item.Value));
+
+ void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex)
+ {
+ if (array.Length < Count + arrayIndex)
+ throw new ArgumentOutOfRangeException(nameof(array), @"Array has insufficient capacity to support copy.");
+ foreach (var item in ((IEnumerable>)this))
+ array[arrayIndex++] = item;
+ }
+
+ bool ICollection>.Remove(KeyValuePair item) =>
+ ((ICollection)this).Remove(new NameValuePair(item.Key, item.Value));
+
+ IEnumerator> IEnumerable>.GetEnumerator()
+ {
+ foreach (var nvp in this)
+ yield return new KeyValuePair(nvp.Name, nvp.Value);
+ }
+ }
+}
diff --git a/FlashPatcher/TaskService/Native/ADVAPI32.cs b/FlashPatcher/TaskService/Native/ADVAPI32.cs
new file mode 100644
index 0000000..e1be994
--- /dev/null
+++ b/FlashPatcher/TaskService/Native/ADVAPI32.cs
@@ -0,0 +1,363 @@
+using System;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Microsoft.Win32
+{
+ internal static partial class NativeMethods
+ {
+ const string ADVAPI32 = "advapi32.dll";
+
+ [Flags]
+ public enum AccessTypes : uint
+ {
+ TokenAssignPrimary = 0x0001,
+ TokenDuplicate = 0x0002,
+ TokenImpersonate = 0x0004,
+ TokenQuery = 0x0008,
+ TokenQuerySource = 0x0010,
+ TokenAdjustPrivileges = 0x0020,
+ TokenAdjustGroups = 0x0040,
+ TokenAdjustDefault = 0x0080,
+ TokenAdjustSessionID = 0x0100,
+ TokenAllAccessP = 0x000F00FF,
+ TokenAllAccess = 0x000F01FF,
+ TokenRead = 0x00020008,
+ TokenWrite = 0x000200E0,
+ TokenExecute = 0x00020000,
+
+ Delete = 0x00010000,
+ ReadControl = 0x00020000,
+ WriteDac = 0x00040000,
+ WriteOwner = 0x00080000,
+ Synchronize = 0x00100000,
+ StandardRightsRequired = 0x000F0000,
+ StandardRightsRead = 0x00020000,
+ StandardRightsWrite = 0x00020000,
+ StandardRightsExecute = 0x00020000,
+ StandardRightsAll = 0x001F0000,
+ SpecificRightsAll = 0x0000FFFF,
+ AccessSystemSecurity = 0x01000000,
+ MaximumAllowed = 0x02000000,
+ GenericRead = 0x80000000,
+ GenericWrite = 0x40000000,
+ GenericExecute = 0x20000000,
+ GenericAll = 0x10000000,
+ }
+
+ [Flags]
+ public enum PrivilegeAttributes : uint
+ {
+ Disabled = 0x00000000,
+ EnabledByDefault = 0x00000001,
+ Enabled = 0x00000002,
+ UsedForAccess = 0x80000000,
+ }
+
+ public enum SECURITY_IMPERSONATION_LEVEL
+ {
+ Anonymous,
+ Identification,
+ Impersonation,
+ Delegation
+ }
+
+ public enum TOKEN_ELEVATION_TYPE
+ {
+ Default = 1,
+ Full,
+ Limited
+ }
+
+ public enum TOKEN_INFORMATION_CLASS
+ {
+ TokenUser = 1,
+ TokenGroups,
+ TokenPrivileges,
+ TokenOwner,
+ TokenPrimaryGroup,
+ TokenDefaultDacl,
+ TokenSource,
+ TokenType,
+ TokenImpersonationLevel,
+ TokenStatistics,
+ TokenRestrictedSids,
+ TokenSessionId,
+ TokenGroupsAndPrivileges,
+ TokenSessionReference,
+ TokenSandBoxInert,
+ TokenAuditPolicy,
+ TokenOrigin,
+ TokenElevationType,
+ TokenLinkedToken,
+ TokenElevation,
+ TokenHasRestrictions,
+ TokenAccessInformation,
+ TokenVirtualizationAllowed,
+ TokenVirtualizationEnabled,
+ TokenIntegrityLevel,
+ TokenUIAccess,
+ TokenMandatoryPolicy,
+ TokenLogonSid,
+ MaxTokenInfoClass
+ }
+
+ [Serializable]
+ public enum TokenType
+ {
+ TokenImpersonation = 2,
+ TokenPrimary = 1
+ }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern bool AdjustTokenPrivileges([In] SafeTokenHandle TokenHandle, [In] bool DisableAllPrivileges, [In] ref TOKEN_PRIVILEGES NewState, [In] uint BufferLength, [In, Out] ref TOKEN_PRIVILEGES PreviousState, [In, Out] ref uint ReturnLength);
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern bool AdjustTokenPrivileges([In] SafeTokenHandle TokenHandle, [In] bool DisableAllPrivileges, [In] ref TOKEN_PRIVILEGES NewState, [In] uint BufferLength, [In] IntPtr PreviousState, [In] IntPtr ReturnLength);
+
+ [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern bool ConvertStringSidToSid([In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid, ref IntPtr sid);
+
+ [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public extern static bool DuplicateToken(SafeTokenHandle ExistingTokenHandle, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, out SafeTokenHandle DuplicateTokenHandle);
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DuplicateTokenEx([In] SafeTokenHandle ExistingTokenHandle, [In] AccessTypes DesiredAccess, [In] IntPtr TokenAttributes, [In] SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [In] TokenType TokenType, [In, Out] ref SafeTokenHandle DuplicateTokenHandle);
+
+ [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern IntPtr GetSidSubAuthority(IntPtr pSid, UInt32 nSubAuthority);
+
+ [DllImport(ADVAPI32, CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTokenInformation(SafeTokenHandle hToken, TOKEN_INFORMATION_CLASS tokenInfoClass, IntPtr pTokenInfo, Int32 tokenInfoLength, out Int32 returnLength);
+
+ [DllImport(ADVAPI32, ExactSpelling = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
+
+ [DllImport(ADVAPI32, SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern int LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
+
+ [DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern bool LookupAccountSid(string systemName, byte[] accountSid, StringBuilder accountName, ref int nameLength, StringBuilder domainName, ref int domainLength, out int accountType);
+
+ [DllImport(ADVAPI32, CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern bool LookupAccountSid([In, MarshalAs(UnmanagedType.LPTStr)] string systemName, IntPtr sid, StringBuilder name, ref int cchName, StringBuilder referencedDomainName, ref int cchReferencedDomainName, out int use);
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool LookupPrivilegeValue(string systemName, string name, out LUID luid);
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool OpenProcessToken(IntPtr ProcessHandle, AccessTypes DesiredAccess, out SafeTokenHandle TokenHandle);
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool OpenThreadToken(IntPtr ThreadHandle, AccessTypes DesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool OpenAsSelf, out SafeTokenHandle TokenHandle);
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool PrivilegeCheck(IntPtr ClientToken, ref PRIVILEGE_SET RequiredPrivileges, out int result);
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool RevertToSelf();
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetThreadToken(IntPtr ThreadHandle, SafeTokenHandle TokenHandle);
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct LUID
+ {
+ public uint LowPart;
+ public int HighPart;
+
+ public static LUID FromName(string name, string systemName = null)
+ {
+ LUID val;
+ if (!NativeMethods.LookupPrivilegeValue(systemName, name, out val))
+ throw new System.ComponentModel.Win32Exception();
+ return val;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct LUID_AND_ATTRIBUTES
+ {
+ public LUID Luid;
+ public PrivilegeAttributes Attributes;
+
+ public LUID_AND_ATTRIBUTES(LUID luid, PrivilegeAttributes attr)
+ {
+ Luid = luid;
+ Attributes = attr;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct PRIVILEGE_SET : IDisposable
+ {
+ public uint PrivilegeCount;
+ public uint Control;
+ public IntPtr Privilege;
+
+ public PRIVILEGE_SET(uint control, params LUID_AND_ATTRIBUTES[] privileges)
+ {
+ PrivilegeCount = (uint)privileges.Length;
+ Control = control;
+ Privilege = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)) * (int)PrivilegeCount);
+ for (int i = 0; i < PrivilegeCount; i++)
+ Marshal.StructureToPtr(privileges[i], (IntPtr)((int)Privilege + (Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)) * i)), false);
+ }
+
+ public void Dispose()
+ {
+ Marshal.FreeHGlobal(Privilege);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SID_AND_ATTRIBUTES
+ {
+ public IntPtr Sid;
+ public UInt32 Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TOKEN_ELEVATION
+ {
+ public Int32 TokenIsElevated;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TOKEN_MANDATORY_LABEL
+ {
+ public SID_AND_ATTRIBUTES Label;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct TOKEN_PRIVILEGES
+ {
+ public uint PrivilegeCount;
+ public LUID_AND_ATTRIBUTES Privileges;
+
+ public TOKEN_PRIVILEGES(LUID luid, PrivilegeAttributes attribute)
+ {
+ PrivilegeCount = 1;
+ Privileges.Luid = luid;
+ Privileges.Attributes = attribute;
+ }
+
+ public static uint SizeInBytes => (uint)Marshal.SizeOf(typeof(TOKEN_PRIVILEGES));
+ }
+
+ public partial class SafeTokenHandle
+ {
+ private const Int32 ERROR_NO_TOKEN = 0x000003F0;
+ private const Int32 ERROR_INSUFFICIENT_BUFFER = 122;
+ private static SafeTokenHandle currentProcessToken = null;
+
+ public T GetInfo(TOKEN_INFORMATION_CLASS type)
+ {
+ int cbSize = Marshal.SizeOf(typeof(T));
+ IntPtr pType = Marshal.AllocHGlobal(cbSize);
+
+ try
+ {
+ // Retrieve token information.
+ if (!NativeMethods.GetTokenInformation(this, type, pType, cbSize, out cbSize))
+ throw new System.ComponentModel.Win32Exception();
+
+ // Marshal from native to .NET.
+ switch (type)
+ {
+ case TOKEN_INFORMATION_CLASS.TokenType:
+ case TOKEN_INFORMATION_CLASS.TokenImpersonationLevel:
+ case TOKEN_INFORMATION_CLASS.TokenSessionId:
+ case TOKEN_INFORMATION_CLASS.TokenSandBoxInert:
+ case TOKEN_INFORMATION_CLASS.TokenOrigin:
+ case TOKEN_INFORMATION_CLASS.TokenElevationType:
+ case TOKEN_INFORMATION_CLASS.TokenHasRestrictions:
+ case TOKEN_INFORMATION_CLASS.TokenUIAccess:
+ case TOKEN_INFORMATION_CLASS.TokenVirtualizationAllowed:
+ case TOKEN_INFORMATION_CLASS.TokenVirtualizationEnabled:
+ return (T)Convert.ChangeType(Marshal.ReadInt32(pType), typeof(T));
+
+ case TOKEN_INFORMATION_CLASS.TokenLinkedToken:
+ return (T)Convert.ChangeType(Marshal.ReadIntPtr(pType), typeof(T));
+
+ case TOKEN_INFORMATION_CLASS.TokenUser:
+ case TOKEN_INFORMATION_CLASS.TokenGroups:
+ case TOKEN_INFORMATION_CLASS.TokenPrivileges:
+ case TOKEN_INFORMATION_CLASS.TokenOwner:
+ case TOKEN_INFORMATION_CLASS.TokenPrimaryGroup:
+ case TOKEN_INFORMATION_CLASS.TokenDefaultDacl:
+ case TOKEN_INFORMATION_CLASS.TokenSource:
+ case TOKEN_INFORMATION_CLASS.TokenStatistics:
+ case TOKEN_INFORMATION_CLASS.TokenRestrictedSids:
+ case TOKEN_INFORMATION_CLASS.TokenGroupsAndPrivileges:
+ case TOKEN_INFORMATION_CLASS.TokenElevation:
+ case TOKEN_INFORMATION_CLASS.TokenAccessInformation:
+ case TOKEN_INFORMATION_CLASS.TokenIntegrityLevel:
+ case TOKEN_INFORMATION_CLASS.TokenMandatoryPolicy:
+ case TOKEN_INFORMATION_CLASS.TokenLogonSid:
+ return (T)Marshal.PtrToStructure(pType, typeof(T));
+
+ case TOKEN_INFORMATION_CLASS.TokenSessionReference:
+ case TOKEN_INFORMATION_CLASS.TokenAuditPolicy:
+ default:
+ return default(T);
+ }
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(pType);
+ }
+ }
+
+ public static SafeTokenHandle FromCurrentProcess(AccessTypes desiredAccess = AccessTypes.TokenDuplicate)
+ {
+ lock (currentProcessToken)
+ {
+ if (currentProcessToken == null)
+ currentProcessToken = FromProcess(NativeMethods.GetCurrentProcess(), desiredAccess);
+ return currentProcessToken;
+ }
+ }
+
+ public static SafeTokenHandle FromCurrentThread(AccessTypes desiredAccess = AccessTypes.TokenDuplicate, bool openAsSelf = true) => FromThread(NativeMethods.GetCurrentThread(), desiredAccess, openAsSelf);
+
+ public static SafeTokenHandle FromProcess(IntPtr hProcess, AccessTypes desiredAccess = AccessTypes.TokenDuplicate)
+ {
+ SafeTokenHandle val;
+ if (!NativeMethods.OpenProcessToken(hProcess, desiredAccess, out val))
+ throw new System.ComponentModel.Win32Exception();
+ return val;
+ }
+
+ public static SafeTokenHandle FromThread(IntPtr hThread, AccessTypes desiredAccess = AccessTypes.TokenDuplicate, bool openAsSelf = true)
+ {
+ SafeTokenHandle val;
+ if (!NativeMethods.OpenThreadToken(hThread, desiredAccess, openAsSelf, out val))
+ {
+ if (Marshal.GetLastWin32Error() == ERROR_NO_TOKEN)
+ {
+ SafeTokenHandle pval = FromCurrentProcess();
+ if (!NativeMethods.DuplicateTokenEx(pval, AccessTypes.TokenImpersonate | desiredAccess, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.Impersonation, TokenType.TokenImpersonation, ref val))
+ throw new System.ComponentModel.Win32Exception();
+ if (!NativeMethods.SetThreadToken(IntPtr.Zero, val))
+ throw new System.ComponentModel.Win32Exception();
+ }
+ else
+ throw new System.ComponentModel.Win32Exception();
+ }
+ return val;
+ }
+ }
+ }
+}
diff --git a/FlashPatcher/TaskService/Native/AccessControlExtension.cs b/FlashPatcher/TaskService/Native/AccessControlExtension.cs
new file mode 100644
index 0000000..e68c356
--- /dev/null
+++ b/FlashPatcher/TaskService/Native/AccessControlExtension.cs
@@ -0,0 +1,89 @@
+using System.Linq;
+
+namespace System.Security.AccessControl
+{
+ /// Extensions for classes in the System.Security.AccessControl namespace.
+ public static class AccessControlExtension
+ {
+ /// Canonicalizes the specified Access Control List.
+ /// The Access Control List.
+ public static void Canonicalize(this RawAcl acl)
+ {
+ if (acl == null) throw new ArgumentNullException(nameof(acl));
+
+ // Extract aces to list
+ var aces = new Collections.Generic.List(acl.Cast());
+
+ // Sort aces based on canonical order
+ aces.Sort((a, b) => Collections.Generic.Comparer.Default.Compare(GetComparisonValue(a), GetComparisonValue(b)));
+
+ // Add sorted aces back to ACL
+ while (acl.Count > 0) acl.RemoveAce(0);
+ var aceIndex = 0;
+ aces.ForEach(ace => acl.InsertAce(aceIndex++, ace));
+ }
+
+ /// Sort ACEs according to canonical form for this .
+ /// The object security whose DiscretionaryAcl will be made canonical.
+ public static void CanonicalizeAccessRules(this ObjectSecurity objectSecurity)
+ {
+ if (objectSecurity == null) throw new ArgumentNullException(nameof(objectSecurity));
+ if (objectSecurity.AreAccessRulesCanonical) return;
+
+ // Get raw SD from objectSecurity and canonicalize DACL
+ var sd = new RawSecurityDescriptor(objectSecurity.GetSecurityDescriptorBinaryForm(), 0);
+ sd.DiscretionaryAcl.Canonicalize();
+
+ // Convert SD back into objectSecurity
+ objectSecurity.SetSecurityDescriptorBinaryForm(sd.GetBinaryForm());
+ }
+
+ /// Returns an array of byte values that represents the information contained in this object.
+ /// The object.
+ /// The byte array into which the contents of the is marshaled.
+ public static byte[] GetBinaryForm(this GenericSecurityDescriptor sd)
+ {
+ if (sd == null) throw new ArgumentNullException(nameof(sd));
+ var bin = new byte[sd.BinaryLength];
+ sd.GetBinaryForm(bin, 0);
+ return bin;
+ }
+
+ // A canonical ACL must have ACES sorted according to the following order:
+ // 1. Access-denied on the object
+ // 2. Access-denied on a child or property
+ // 3. Access-allowed on the object
+ // 4. Access-allowed on a child or property
+ // 5. All inherited ACEs
+ private static byte GetComparisonValue(GenericAce ace)
+ {
+ if ((ace.AceFlags & AceFlags.Inherited) != 0)
+ return 5;
+ switch (ace.AceType)
+ {
+ case AceType.AccessDenied:
+ case AceType.AccessDeniedCallback:
+ case AceType.SystemAudit:
+ case AceType.SystemAlarm:
+ case AceType.SystemAuditCallback:
+ case AceType.SystemAlarmCallback:
+ return 0;
+ case AceType.AccessDeniedObject:
+ case AceType.AccessDeniedCallbackObject:
+ case AceType.SystemAuditObject:
+ case AceType.SystemAlarmObject:
+ case AceType.SystemAuditCallbackObject:
+ case AceType.SystemAlarmCallbackObject:
+ return 1;
+ case AceType.AccessAllowed:
+ case AceType.AccessAllowedCallback:
+ return 2;
+ case AceType.AccessAllowedObject:
+ case AceType.AccessAllowedCallbackObject:
+ return 3;
+ default:
+ return 4;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/FlashPatcher/TaskService/Native/EnumUtil.cs b/FlashPatcher/TaskService/Native/EnumUtil.cs
new file mode 100644
index 0000000..814660c
--- /dev/null
+++ b/FlashPatcher/TaskService/Native/EnumUtil.cs
@@ -0,0 +1,147 @@
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+
+namespace System
+{
+ internal static class EnumUtil
+ {
+ public static void CheckIsEnum(bool checkHasFlags = false)
+ {
+ if (!typeof(T).IsEnum)
+ throw new ArgumentException($"Type '{typeof(T).FullName}' is not an enum");
+ if (checkHasFlags && !IsFlags())
+ throw new ArgumentException($"Type '{typeof(T).FullName}' doesn't have the 'Flags' attribute");
+ }
+
+ public static bool IsFlags() => Attribute.IsDefined(typeof(T), typeof(FlagsAttribute));
+
+ public static void CheckHasValue(T value, string argName = null)
+ {
+ CheckIsEnum();
+ if (IsFlags())
+ {
+ var allFlags = 0L;
+ foreach (T flag in Enum.GetValues(typeof(T)))
+ allFlags |= Convert.ToInt64(flag);
+ if ((allFlags & Convert.ToInt64(value)) != 0L)
+ return;
+ }
+ else if (Enum.IsDefined(typeof(T), value))
+ return;
+ throw new InvalidEnumArgumentException(argName ?? "value", Convert.ToInt32(value), typeof(T));
+ }
+
+ public static byte BitPosition(this T flags) where T : struct, IConvertible
+ {
+ CheckIsEnum(true);
+ var flagValue = Convert.ToInt64(flags);
+ if (flagValue == 0) throw new ArgumentException("The flag value is zero and has no bit position.");
+ var r = Math.Log(flagValue, 2);
+ if (r % 1 > 0) throw new ArithmeticException("The flag value has more than a single bit set.");
+ return Convert.ToByte(r);
+ }
+
+ public static bool IsFlagSet(this T flags, T flag) where T : struct, IConvertible
+ {
+ CheckIsEnum(true);
+ var flagValue = Convert.ToInt64(flag);
+ return (Convert.ToInt64(flags) & flagValue) == flagValue;
+ }
+
+ public static bool IsValidFlagValue(this T flags) where T : struct, IConvertible
+ {
+ CheckIsEnum(true);
+ var found = 0L;
+ foreach (T flag in Enum.GetValues(typeof(T)))
+ {
+ if (flags.IsFlagSet(flag))
+ found |= Convert.ToInt64(flag);
+ }
+ return found == Convert.ToInt64(flags);
+ }
+
+ public static void SetFlags(ref T flags, T flag, bool set = true) where T : struct, IConvertible
+ {
+ CheckIsEnum(true);
+ var flagsValue = Convert.ToInt64(flags);
+ var flagValue = Convert.ToInt64(flag);
+ if (set)
+ flagsValue |= flagValue;
+ else
+ flagsValue &= (~flagValue);
+ flags = (T)Enum.ToObject(typeof(T), flagsValue);
+ }
+
+ public static T SetFlags(this T flags, T flag, bool set = true) where T : struct, IConvertible
+ {
+ var ret = flags;
+ SetFlags(ref ret, flag, set);
+ return ret;
+ }
+
+ public static T ClearFlags(this T flags, T flag) where T : struct, IConvertible => flags.SetFlags(flag, false);
+
+ public static IEnumerable GetFlags(this T value) where T : struct, IConvertible
+ {
+ CheckIsEnum(true);
+ foreach (T flag in Enum.GetValues(typeof(T)))
+ {
+ if (value.IsFlagSet(flag))
+ yield return flag;
+ }
+ }
+
+ public static T CombineFlags(this IEnumerable flags) where T : struct, IConvertible
+ {
+ CheckIsEnum(true);
+ long lValue = 0;
+ foreach (var flag in flags)
+ {
+ var lFlag = Convert.ToInt64(flag);
+ lValue |= lFlag;
+ }
+ return (T)Enum.ToObject(typeof(T), lValue);
+ }
+
+ public static string GetDescription(this T value) where T : struct, IConvertible
+ {
+ CheckIsEnum();
+ var name = Enum.GetName(typeof(T), value);
+ if (name != null)
+ {
+ var field = typeof(T).GetField(name);
+ if (field != null)
+ {
+ var attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
+ if (attr != null)
+ {
+ return attr.Description;
+ }
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object or returns the value of . If is undefined, it returns the first declared item in the enumerated type.
+ ///
+ /// The enumeration type to which to convert .
+ /// The string representation of the enumeration name or underlying value to convert.
+ /// true to ignore case; false to consider case.
+ /// The default value.
+ /// An object of type whose value is represented by value.
+ public static TEnum TryParse(string value, bool ignoreCase = false, TEnum defaultVal = default(TEnum)) where TEnum : struct, IConvertible
+ {
+ CheckIsEnum();
+ try { return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase); } catch { }
+ if (!Enum.IsDefined(typeof(TEnum), defaultVal))
+ {
+ var v = Enum.GetValues(typeof(TEnum));
+ if (v != null && v.Length > 0)
+ return (TEnum)v.GetValue(0);
+ }
+ return defaultVal;
+ }
+ }
+}
diff --git a/FlashPatcher/TaskService/Native/EventLog.cs b/FlashPatcher/TaskService/Native/EventLog.cs
new file mode 100644
index 0000000..ccc2ba9
--- /dev/null
+++ b/FlashPatcher/TaskService/Native/EventLog.cs
@@ -0,0 +1,5882 @@
+#if NET20
+/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ * Event methods and classes literally pulled from the .NET 4.0 implementation.
+ * None of this is original work. It comes straight from decompiled Microsoft
+ * assemblies.
+ * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+using Microsoft.Win32.SafeHandles;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.IO;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Security.Permissions;
+using System.Security.Principal;
+using System.Text;
+using System.Threading;
+
+namespace System.Diagnostics.Eventing.Reader
+{
+ ///
+ public enum EventLogIsolation
+ {
+ /// The application
+ Application,
+
+ /// The system
+ System,
+
+ /// The custom
+ Custom
+ }
+
+ ///
+ public enum EventLogMode
+ {
+ /// The circular
+ Circular,
+
+ /// The automatic backup
+ AutoBackup,
+
+ /// The retain
+ Retain
+ }
+
+ ///
+ public enum EventLogType
+ {
+ /// The administrative
+ Administrative,
+
+ /// The operational
+ Operational,
+
+ /// The analytical
+ Analytical,
+
+ /// The debug
+ Debug
+ }
+
+ /// PathType
+ public enum PathType
+ {
+ /// The file path
+ FilePath = 2,
+
+ /// The log name
+ LogName = 1
+ }
+
+ /// SessionAuthentication
+ public enum SessionAuthentication
+ {
+ /// The default
+ Default,
+
+ /// The negotiate
+ Negotiate,
+
+ /// The kerberos
+ Kerberos,
+
+ /// The NTLM
+ Ntlm
+ }
+
+ /// Defines the standard keywords that are attached to events by the event provider. For more information about keywords, see .
+ [Flags]
+ public enum StandardEventKeywords : long
+ {
+ /// The audit failure
+ AuditFailure = 0x10000000000000L,
+
+ /// The audit success
+ AuditSuccess = 0x20000000000000L,
+
+ /// The correlation hint
+ [Obsolete("Incorrect value: use CorrelationHint2 instead", false)]
+ CorrelationHint = 0x10000000000000L,
+
+ /// The correlation hint2
+ CorrelationHint2 = 0x40000000000000L,
+
+ /// The event log classic
+ EventLogClassic = 0x80000000000000L,
+
+ /// The none
+ None = 0L,
+
+ /// The response time
+ ResponseTime = 0x01000000000000L,
+
+ /// The SQM
+ Sqm = 0x08000000000000L,
+
+ /// The wdi context
+ WdiContext = 0x02000000000000L,
+
+ /// The wdi diagnostic
+ WdiDiagnostic = 0x04000000000000L
+ }
+
+ ///
+ /// Represents a placeholder (bookmark) within an event stream. You can use the placeholder to mark a position and return to this position in a stream of
+ /// events. An instance of this object can be obtained from an EventRecord object, in which case it corresponds to the position of that event record.
+ ///
+ [Serializable]
+ public class EventBookmark : ISerializable
+ {
+ // Fields
+ private string bookmark;
+
+ // Methods
+ internal EventBookmark(string bookmarkText)
+ {
+ if (bookmarkText == null)
+ {
+ throw new ArgumentNullException(nameof(bookmarkText));
+ }
+ bookmark = bookmarkText;
+ }
+
+ /// Initializes a new instance of the class.
+ /// The information.
+ /// The context.
+ protected EventBookmark(SerializationInfo info, StreamingContext context)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException(nameof(info));
+ }
+ bookmark = info.GetString("BookmarkText");
+ }
+
+ // Properties
+ internal string BookmarkText => bookmark;
+
+ [SecurityCritical, SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
+ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ GetObjectData(info, context);
+ }
+
+ /// Gets the object data.
+ /// The information.
+ /// The context.
+ [SecurityCritical, SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
+ protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException(nameof(info));
+ }
+ info.AddValue("BookmarkText", bookmark);
+ }
+ }
+
+ ///
+ /// Represents a keyword for an event. Keywords are defined in an event provider and are used to group the event with other similar events (based on the
+ /// usage of the events).
+ ///
+ public sealed class EventKeyword
+ {
+ // Fields
+ private bool dataReady;
+
+ private string displayName;
+ private string name;
+ private ProviderMetadata pmReference;
+ private object syncObject;
+ private long value;
+
+ // Methods
+ internal EventKeyword(long value, ProviderMetadata pmReference)
+ {
+ this.value = value;
+ this.pmReference = pmReference;
+ syncObject = new object();
+ }
+
+ internal EventKeyword(string name, long value, string displayName)
+ {
+ this.value = value;
+ this.name = name;
+ this.displayName = displayName;
+ dataReady = true;
+ syncObject = new object();
+ }
+
+ // Properties
+ /// Gets the display name.
+ /// The display name.
+ public string DisplayName
+ {
+ get
+ {
+ PrepareData();
+ return displayName;
+ }
+ }
+
+ /// Gets the name.
+ /// The name.
+ public string Name
+ {
+ get
+ {
+ PrepareData();
+ return name;
+ }
+ }
+
+ /// Gets the value.
+ /// The value.
+ public long Value => value;
+
+ internal void PrepareData()
+ {
+ if (!dataReady)
+ {
+ lock (syncObject)
+ {
+ if (!dataReady)
+ {
+ IEnumerable keywords = pmReference.Keywords;
+ name = null;
+ displayName = null;
+ dataReady = true;
+ foreach (EventKeyword keyword in keywords)
+ {
+ if (keyword.Value == value)
+ {
+ name = keyword.Name;
+ displayName = keyword.DisplayName;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// Contains an event level that is defined in an event provider. The level signifies the severity of the event.
+ public sealed class EventLevel
+ {
+ // Fields
+ private bool dataReady;
+
+ private string displayName;
+ private string name;
+ private ProviderMetadata pmReference;
+ private object syncObject;
+ private int value;
+
+ // Methods
+ internal EventLevel(int value, ProviderMetadata pmReference)
+ {
+ this.value = value;
+ this.pmReference = pmReference;
+ syncObject = new object();
+ }
+
+ internal EventLevel(string name, int value, string displayName)
+ {
+ this.value = value;
+ this.name = name;
+ this.displayName = displayName;
+ dataReady = true;
+ syncObject = new object();
+ }
+
+ // Properties
+ /// Gets the display name.
+ /// The display name.
+ public string DisplayName
+ {
+ get
+ {
+ PrepareData();
+ return displayName;
+ }
+ }
+
+ /// Gets the name.
+ /// The name.
+ public string Name
+ {
+ get
+ {
+ PrepareData();
+ return name;
+ }
+ }
+
+ /// Gets the value.
+ /// The value.
+ public int Value => value;
+
+ internal void PrepareData()
+ {
+ if (!dataReady)
+ {
+ lock (syncObject)
+ {
+ if (!dataReady)
+ {
+ IEnumerable levels = pmReference.Levels;
+ name = null;
+ displayName = null;
+ dataReady = true;
+ foreach (EventLevel level in levels)
+ {
+ if (level.Value == value)
+ {
+ name = level.Name;
+ displayName = level.DisplayName;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// EventLogConfiguration
+ public class EventLogConfiguration : IDisposable
+ {
+ private string channelName;
+ private EventLogHandle handle;
+ private EventLogSession session;
+
+ /// Initializes a new instance of the class.
+ /// Name of the log.
+ public EventLogConfiguration(string logName) : this(logName, null) { }
+
+ /// Initializes a new instance of the class.
+ /// Name of the log.
+ /// The session.
+ [SecurityCritical]
+ public EventLogConfiguration(string logName, EventLogSession session)
+ {
+ handle = EventLogHandle.Zero;
+ EventLogPermissionHolder.GetEventLogPermission().Demand();
+ if (session == null)
+ {
+ session = EventLogSession.GlobalSession;
+ }
+ this.session = session;
+ channelName = logName;
+ handle = NativeWrapper.EvtOpenChannelConfig(this.session.Handle, channelName, 0);
+ }
+
+ // Properties
+ /// Gets a value indicating whether this instance is classic log.
+ /// true if this instance is classic log; otherwise, false.
+ public bool IsClassicLog => (bool)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigClassicEventlog);
+
+ /// Gets or sets a value indicating whether this instance is enabled.
+ /// true if this instance is enabled; otherwise, false.
+ public bool IsEnabled
+ {
+ get
+ {
+ return (bool)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigEnabled);
+ }
+ set
+ {
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigEnabled, value);
+ }
+ }
+
+ /// Gets or sets the log file path.
+ /// The log file path.
+ public string LogFilePath
+ {
+ get
+ {
+ return (string)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath);
+ }
+ set
+ {
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigLogFilePath, value);
+ }
+ }
+
+ /// Gets the log isolation.
+ /// The log isolation.
+ public EventLogIsolation LogIsolation => (EventLogIsolation)((uint)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigIsolation));
+
+ /// Gets or sets the log mode.
+ /// The log mode.
+ public EventLogMode LogMode
+ {
+ get
+ {
+ object obj2 = NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention);
+ object obj3 = NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup);
+ bool flag = (obj2 != null) && ((bool)obj2);
+ if ((obj3 != null) && ((bool)obj3))
+ {
+ return EventLogMode.AutoBackup;
+ }
+ if (flag)
+ {
+ return EventLogMode.Retain;
+ }
+ return EventLogMode.Circular;
+ }
+ set
+ {
+ switch (value)
+ {
+ case EventLogMode.Circular:
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, false);
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, false);
+ return;
+
+ case EventLogMode.AutoBackup:
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, true);
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, true);
+ return;
+
+ case EventLogMode.Retain:
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigAutoBackup, false);
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigRetention, true);
+ return;
+ }
+ }
+ }
+
+ /// Gets the name of the log.
+ /// The name of the log.
+ public string LogName => channelName;
+
+ /// Gets the type of the log.
+ /// The type of the log.
+ public EventLogType LogType => (EventLogType)((uint)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigType));
+
+ /// Gets or sets the maximum size in bytes.
+ /// The maximum size in bytes.
+ public long MaximumSizeInBytes
+ {
+ get
+ {
+ return (long)((ulong)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize));
+ }
+ set
+ {
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelLoggingConfigMaxSize, value);
+ }
+ }
+
+ /// Gets the name of the owning provider.
+ /// The name of the owning provider.
+ public string OwningProviderName => (string)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigOwningPublisher);
+
+ /// Gets the size of the provider buffer.
+ /// The size of the provider buffer.
+ public int? ProviderBufferSize
+ {
+ get
+ {
+ uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigBufferSize);
+ if (!nullable.HasValue)
+ {
+ return null;
+ }
+ return new int?((int)nullable.GetValueOrDefault());
+ }
+ }
+
+ /// Gets the provider control unique identifier.
+ /// The provider control unique identifier.
+ public Guid? ProviderControlGuid => (Guid?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigControlGuid);
+
+ /// Gets or sets the provider keywords.
+ /// The provider keywords.
+ public long? ProviderKeywords
+ {
+ get
+ {
+ ulong? nullable = (ulong?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords);
+ if (!nullable.HasValue)
+ {
+ return null;
+ }
+ return new long?((long)nullable.GetValueOrDefault());
+ }
+ set
+ {
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigKeywords, value);
+ }
+ }
+
+ /// Gets the provider latency.
+ /// The provider latency.
+ public int? ProviderLatency
+ {
+ get
+ {
+ uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLatency);
+ if (!nullable.HasValue)
+ {
+ return null;
+ }
+ return new int?((int)nullable.GetValueOrDefault());
+ }
+ }
+
+ /// Gets or sets the provider level.
+ /// The provider level.
+ public int? ProviderLevel
+ {
+ get
+ {
+ uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel);
+ if (!nullable.HasValue)
+ {
+ return null;
+ }
+ return new int?((int)nullable.GetValueOrDefault());
+ }
+ set
+ {
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigLevel, value);
+ }
+ }
+
+ /// Gets the provider maximum number of buffers.
+ /// The provider maximum number of buffers.
+ public int? ProviderMaximumNumberOfBuffers
+ {
+ get
+ {
+ uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigMaxBuffers);
+ if (!nullable.HasValue)
+ {
+ return null;
+ }
+ return new int?((int)nullable.GetValueOrDefault());
+ }
+ }
+
+ /// Gets the provider minimum number of buffers.
+ /// The provider minimum number of buffers.
+ public int? ProviderMinimumNumberOfBuffers
+ {
+ get
+ {
+ uint? nullable = (uint?)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublishingConfigMinBuffers);
+ if (!nullable.HasValue)
+ {
+ return null;
+ }
+ return new int?((int)nullable.GetValueOrDefault());
+ }
+ }
+
+ /// Gets the provider names.
+ /// The provider names.
+ public IEnumerable ProviderNames => (string[])NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelPublisherList);
+
+ /// Gets or sets the security descriptor.
+ /// The security descriptor.
+ public string SecurityDescriptor
+ {
+ get
+ {
+ return (string)NativeWrapper.EvtGetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess);
+ }
+ set
+ {
+ NativeWrapper.EvtSetChannelConfigProperty(handle, UnsafeNativeMethods.EvtChannelConfigPropertyId.EvtChannelConfigAccess, value);
+ }
+ }
+
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// Saves the changes.
+ public void SaveChanges()
+ {
+ NativeWrapper.EvtSaveChannelConfig(handle, 0);
+ }
+
+ /// Releases unmanaged and - optionally - managed resources.
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ [SecuritySafeCritical]
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ EventLogPermissionHolder.GetEventLogPermission().Demand();
+ }
+ if ((handle != null) && !handle.IsInvalid)
+ {
+ handle.Dispose();
+ }
+ }
+ }
+
+ ///
+ /// Allows you to access the run-time properties of active event logs and event log files. These properties include the number of events in the log, the size of the log, a value that determines whether the log is full, and the last time the log was written to or accessed.
+ ///
+ public sealed class EventLogInformation
+ {
+ // Fields
+ private DateTime? creationTime;
+
+ private int? fileAttributes;
+ private long? fileSize;
+ private bool? isLogFull;
+ private DateTime? lastAccessTime;
+ private DateTime? lastWriteTime;
+ private long? oldestRecordNumber;
+ private long? recordCount;
+
+ // Methods
+ [SecurityCritical]
+ internal EventLogInformation(EventLogSession session, string channelName, PathType pathType)
+ {
+ EventLogPermissionHolder.GetEventLogPermission().Demand();
+ EventLogHandle handle = NativeWrapper.EvtOpenLog(session.Handle, channelName, pathType);
+ using (handle)
+ {
+ creationTime = (DateTime?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogCreationTime);
+ lastAccessTime = (DateTime?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogLastAccessTime);
+ lastWriteTime = (DateTime?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogLastWriteTime);
+ ulong? nullable = (ulong?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogFileSize);
+ fileSize = nullable.HasValue ? (long?)(nullable.GetValueOrDefault()) : null;
+ uint? nullable3 = (uint?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogAttributes);
+ fileAttributes = nullable3.HasValue ? (int?)(nullable3.GetValueOrDefault()) : null;
+ ulong? nullable5 = (ulong?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogNumberOfLogRecords);
+ recordCount = nullable5.HasValue ? (long?)(nullable5.GetValueOrDefault()) : null;
+ ulong? nullable7 = (ulong?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogOldestRecordNumber);
+ oldestRecordNumber = nullable7.HasValue ? (long?)(nullable7.GetValueOrDefault()) : null;
+ isLogFull = (bool?)NativeWrapper.EvtGetLogInfo(handle, UnsafeNativeMethods.EvtLogPropertyId.EvtLogFull);
+ }
+ }
+
+ // Properties
+ /// Gets the attributes.
+ /// The attributes.
+ public int? Attributes => fileAttributes;
+
+ /// Gets the creation time.
+ /// The creation time.
+ public DateTime? CreationTime => creationTime;
+
+ /// Gets the size of the file.
+ /// The size of the file.
+ public long? FileSize => fileSize;
+
+ /// Gets the is log full.
+ /// The is log full.
+ public bool? IsLogFull => isLogFull;
+
+ /// Gets the last access time.
+ /// The last access time.
+ public DateTime? LastAccessTime => lastAccessTime;
+
+ /// Gets the last write time.
+ /// The last write time.
+ public DateTime? LastWriteTime => lastWriteTime;
+
+ /// Gets the oldest record number.
+ /// The oldest record number.
+ public long? OldestRecordNumber => oldestRecordNumber;
+
+ /// Gets the record count.
+ /// The record count.
+ public long? RecordCount => recordCount;
+ }
+
+ ///
+ /// Represents a link between an event provider and an event log that the provider publishes events into. This object cannot be instantiated.
+ ///
+ public sealed class EventLogLink
+ {
+ // Fields
+ private uint channelId;
+
+ private string channelName;
+ private bool dataReady;
+ private string displayName;
+ private bool isImported;
+ private ProviderMetadata pmReference;
+ private object syncObject;
+
+ // Methods
+ internal EventLogLink(uint channelId, ProviderMetadata pmReference)
+ {
+ this.channelId = channelId;
+ this.pmReference = pmReference;
+ syncObject = new object();
+ }
+
+ internal EventLogLink(string channelName, bool isImported, string displayName, uint channelId)
+ {
+ this.channelName = channelName;
+ this.isImported = isImported;
+ this.displayName = displayName;
+ this.channelId = channelId;
+ dataReady = true;
+ syncObject = new object();
+ }
+
+ /// Gets the display name.
+ /// The display name.
+ public string DisplayName
+ {
+ get
+ {
+ PrepareData();
+ return displayName;
+ }
+ }
+
+ /// Gets a value indicating whether this instance is imported.
+ /// true if this instance is imported; otherwise, false.
+ public bool IsImported
+ {
+ get
+ {
+ PrepareData();
+ return isImported;
+ }
+ }
+
+ /// Gets the name of the log.
+ /// The name of the log.
+ public string LogName
+ {
+ get
+ {
+ PrepareData();
+ return channelName;
+ }
+ }
+
+ // Properties
+ internal uint ChannelId => channelId;
+
+ private void PrepareData()
+ {
+ if (!dataReady)
+ {
+ lock (syncObject)
+ {
+ if (!dataReady)
+ {
+ IEnumerable logLinks = pmReference.LogLinks;
+ channelName = null;
+ isImported = false;
+ displayName = null;
+ dataReady = true;
+ foreach (EventLogLink link in logLinks)
+ {
+ if (link.ChannelId == channelId)
+ {
+ channelName = link.LogName;
+ isImported = link.IsImported;
+ displayName = link.DisplayName;
+ dataReady = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Contains an array of strings that represent XPath queries for elements in the XML representation of an event, which is based on the Event Schema. The queries in this object are used to extract values from the event.
+ ///
+ ///
+ public class EventLogPropertySelector : IDisposable
+ {
+ // Fields
+ private EventLogHandle renderContextHandleValues;
+
+ // Methods
+ /// Initializes a new instance of the class.
+ /// The property queries.
+ [SecurityCritical]
+ public EventLogPropertySelector(IEnumerable propertyQueries)
+ {
+ string[] strArray;
+ EventLogPermissionHolder.GetEventLogPermission().Demand();
+ if (propertyQueries == null)
+ {
+ throw new ArgumentNullException(nameof(propertyQueries));
+ }
+ ICollection is2 = propertyQueries as ICollection;
+ if (is2 != null)
+ {
+ strArray = new string[is2.Count];
+ is2.CopyTo(strArray, 0);
+ }
+ else
+ {
+ strArray = new List(propertyQueries).ToArray();
+ }
+ renderContextHandleValues = NativeWrapper.EvtCreateRenderContext(strArray.Length, strArray, UnsafeNativeMethods.EvtRenderContextFlags.EvtRenderContextValues);
+ }
+
+ // Properties
+ internal EventLogHandle Handle => renderContextHandleValues;
+
+ /// Releases unmanaged and - optionally - managed resources.
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// Releases unmanaged and - optionally - managed resources.
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ [SecurityCritical]
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ EventLogPermissionHolder.GetEventLogPermission().Demand();
+ }
+ if ((renderContextHandleValues != null) && !renderContextHandleValues.IsInvalid)
+ {
+ renderContextHandleValues.Dispose();
+ }
+ }
+ }
+
+ ///
+ /// Contains the properties of an event instance for an event that is received from an EventLogReader object. The event properties provide information about the event such as the name of the computer where the event was logged and the time that the event was created.
+ ///
+ ///
+ public class EventLogRecord : EventRecord
+ {
+ private const int SYSTEM_PROPERTY_COUNT = 0x12;
+
+ private ProviderMetadataCachedInformation cachedMetadataInformation;
+ private string containerChannel;
+
+ private EventLogHandle handle;
+ private IEnumerable keywordsNames;
+ private string levelName;
+ private bool levelNameReady;
+ private int[] matchedQueryIds;
+ private string opcodeName;
+ private bool opcodeNameReady;
+ private EventLogSession session;
+ private object syncObject;
+ private NativeWrapper.SystemProperties systemProperties;
+ private string taskName;
+ private bool taskNameReady;
+
+ internal EventLogRecord(EventLogHandle handle, EventLogSession session, ProviderMetadataCachedInformation cachedMetadataInfo)
+ {
+ cachedMetadataInformation = cachedMetadataInfo;
+ this.handle = handle;
+ this.session = session;
+ systemProperties = new NativeWrapper.SystemProperties();
+ syncObject = new object();
+ }
+
+ /// Gets the activity identifier.
+ /// The activity identifier.
+ public override Guid? ActivityId
+ {
+ get
+ {
+ PrepareSystemData();
+ return systemProperties.ActivityId;
+ }
+ }
+
+ /// Gets the bookmark.
+ /// The bookmark.
+ public override EventBookmark Bookmark
+ {
+ [SecurityCritical]
+ get
+ {
+ EventLogPermissionHolder.GetEventLogPermission().Demand();
+ EventLogHandle bookmark = NativeWrapper.EvtCreateBookmark(null);
+ NativeWrapper.EvtUpdateBookmark(bookmark, handle);
+ return new EventBookmark(NativeWrapper.EvtRenderBookmark(bookmark));
+ }
+ }
+
+ /// Gets the container log.
+ /// The container log.
+ public string ContainerLog
+ {
+ get
+ {
+ if (containerChannel != null)
+ {
+ return containerChannel;
+ }
+ lock (syncObject)
+ {
+ if (containerChannel == null)
+ {
+ containerChannel = (string)NativeWrapper.EvtGetEventInfo(Handle, UnsafeNativeMethods.EvtEventPropertyId.EvtEventPath);
+ }
+ return containerChannel;
+ }
+ }
+ }
+
+ /// Gets the identifier.
+ /// The identifier.
+ public override int Id
+ {
+ get
+ {
+ PrepareSystemData();
+ ushort? id = systemProperties.Id;
+ int? nullable3 = id.HasValue ? new int?(id.GetValueOrDefault()) : null;
+ if (!nullable3.HasValue)
+ {
+ return 0;
+ }
+ return systemProperties.Id.Value;
+ }
+ }
+
+ /// Gets the keywords.
+ /// The keywords.
+ public override long? Keywords
+ {
+ get
+ {
+ PrepareSystemData();
+ ulong? keywords = systemProperties.Keywords;
+ if (!keywords.HasValue)
+ {
+ return null;
+ }
+ return (long)(keywords.GetValueOrDefault());
+ }
+ }
+
+ /// Gets the keywords display names.
+ /// The keywords display names.
+ public override IEnumerable KeywordsDisplayNames
+ {
+ get
+ {
+ if (keywordsNames != null)
+ {
+ return keywordsNames;
+ }
+ lock (syncObject)
+ {
+ if (keywordsNames == null)
+ {
+ keywordsNames = cachedMetadataInformation.GetKeywordDisplayNames(ProviderName, handle);
+ }
+ return keywordsNames;
+ }
+ }
+ }
+
+ /// Gets the level.
+ /// The level.
+ public override byte? Level
+ {
+ get
+ {
+ PrepareSystemData();
+ return systemProperties.Level;
+ }
+ }
+
+ /// Gets the display name of the level.
+ /// The display name of the level.
+ public override string LevelDisplayName
+ {
+ get
+ {
+ if (levelNameReady)
+ {
+ return levelName;
+ }
+ lock (syncObject)
+ {
+ if (!levelNameReady)
+ {
+ levelNameReady = true;
+ levelName = cachedMetadataInformation.GetLevelDisplayName(ProviderName, handle);
+ }
+ return levelName;
+ }
+ }
+ }
+
+ /// Gets the name of the log.
+ /// The name of the log.
+ public override string LogName
+ {
+ get
+ {
+ PrepareSystemData();
+ return systemProperties.ChannelName;
+ }
+ }
+
+ /// Gets the name of the machine.
+ /// The name of the machine.
+ public override string MachineName
+ {
+ get
+ {
+ PrepareSystemData();
+ return systemProperties.ComputerName;
+ }
+ }
+
+ /// Gets the matched query ids.
+ /// The matched query ids.
+ public IEnumerable MatchedQueryIds
+ {
+ get
+ {
+ if (matchedQueryIds != null)
+ {
+ return matchedQueryIds;
+ }
+ lock (syncObject)
+ {
+ if (matchedQueryIds == null)
+ {
+ matchedQueryIds = (int[])NativeWrapper.EvtGetEventInfo(Handle, UnsafeNativeMethods.EvtEventPropertyId.EvtEventQueryIDs);
+ }
+ return matchedQueryIds;
+ }
+ }
+ }
+
+ /// Gets the opcode.
+ /// The opcode.
+ public override short? Opcode
+ {
+ get
+ {
+ PrepareSystemData();
+ byte? opcode = systemProperties.Opcode;
+ ushort? nullable3 = opcode.HasValue ? new ushort?(opcode.GetValueOrDefault()) : null;
+ if (!nullable3.HasValue)
+ {
+ return null;
+ }
+ return new short?((short)nullable3.GetValueOrDefault());
+ }
+ }
+
+ /// Gets the display name of the opcode.
+ /// The display name of the opcode.
+ public override string OpcodeDisplayName
+ {
+ get
+ {
+ lock (syncObject)
+ {
+ if (!opcodeNameReady)
+ {
+ opcodeNameReady = true;
+ opcodeName = cachedMetadataInformation.GetOpcodeDisplayName(ProviderName, handle);
+ }
+ return opcodeName;
+ }
+ }
+ }
+
+ /// Gets the process identifier.
+ /// The process identifier.
+ public override int? ProcessId
+ {
+ get
+ {
+ PrepareSystemData();
+ uint? processId = systemProperties.ProcessId;
+ if (!processId.HasValue)
+ {
+ return null;
+ }
+ return (int)processId.GetValueOrDefault();
+ }
+ }
+
+ /// Gets the properties.
+ /// The properties.
+ public override IList Properties
+ {
+ get
+ {
+ session.SetupUserContext();
+ IList