using System;
using System.Runtime.InteropServices;
using System.Text;
using JetBrains.Annotations;
namespace Microsoft.Win32.TaskScheduler
{
///
/// Some string values of properties can be set to retrieve their value from existing DLLs as a resource. This class facilitates creating those reference strings.
///
[PublicAPI]
public class ResourceReferenceValue
{
///
/// Initializes a new instance of the class.
///
/// The DLL path.
/// The resource identifier.
public ResourceReferenceValue([NotNull] string dllPath, int resourceId)
{
ResourceFilePath = dllPath;
ResourceIdentifier = resourceId;
}
///
/// Gets or sets the resource file path. This can be a relative path, full path or lookup path (e.g. %SystemRoot%\System32\ResourceName.dll).
///
///
/// The resource file path.
///
public string ResourceFilePath { get; set; }
///
/// Gets or sets the resource identifier.
///
/// The resource identifier.
public int ResourceIdentifier { get; set; }
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator string(ResourceReferenceValue value) => value.ToString();
///
/// Parses the input string. String must be in the format "$(@ [Dll], [ResourceID])".
///
/// The input string value.
/// A new instance on success or null on failure.
/// is null
/// is not in the format "$(@ [Dll], [ResourceID])"
[NotNull]
public static ResourceReferenceValue Parse([NotNull] string value)
{
if (value == null)
throw new ArgumentNullException(nameof(value));
ResourceReferenceValue r;
if (!TryParse(value, out r))
throw new FormatException();
return r;
}
///
/// Tries to parse to input string. String must be in the format "$(@ [Dll], [ResourceID])".
///
/// The input string value.
/// The resource reference to be returned. On failure, this value equals null.
/// A new instance on success or null on failure.
public static bool TryParse(string value, out ResourceReferenceValue resourceRef)
{
if (!string.IsNullOrEmpty(value))
{
var m = System.Text.RegularExpressions.Regex.Match(value, @"^\$\(\@ (?[^,]+), (?-?\d+)\)$");
if (m.Success)
{
resourceRef = new ResourceReferenceValue(m.Groups["x"].Value, int.Parse(m.Groups["i"].Value));
return true;
}
}
resourceRef = null;
return false;
}
///
/// Gets the result of pulling the string from the resource file using the identifier.
///
/// from resource file.
/// cannot be found.
/// Unable to load or string identified by .
[NotNull]
public string GetResolvedString()
{
if (!System.IO.File.Exists(ResourceFilePath))
throw new System.IO.FileNotFoundException("Invalid resource file path.", ResourceFilePath);
IntPtr hLib = IntPtr.Zero;
try
{
hLib = NativeMethods.LoadLibrary(ResourceFilePath);
if (hLib == IntPtr.Zero)
throw new System.ComponentModel.Win32Exception();
var sb = new StringBuilder(8192);
int l = LoadString(hLib, ResourceIdentifier, sb, sb.Capacity);
if (l == 0)
throw new System.ComponentModel.Win32Exception();
return sb.ToString(0, l);
}
finally
{
if (hLib != IntPtr.Zero)
NativeMethods.FreeLibrary(hLib);
}
}
///
/// Returns a in the format required by the Task Scheduler to reference a string in a DLL.
///
/// A formatted in the format $(@ [Dll], [ResourceID]).
public override string ToString() => $"$(@ {ResourceFilePath}, {ResourceIdentifier})";
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
private static extern int LoadString(IntPtr hInstance, int wID, StringBuilder lpBuffer, int nBufferMax);
}
}