#nullable enable
using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.PInvoke;
namespace Vanara.Windows.Shell
{
/// Wraps a string resource reference used by some Shell classes.
[TypeConverter(typeof(IndirectStringTypeConverter))]
[DebuggerDisplay("{RawValue} => {Value}")]
public class IndirectString : IndirectResource
{
/// Initializes a new instance of the class.
public IndirectString() { }
/// Initializes a new instance of the class.
public IndirectString(string? value) : base(value) { }
/// Initializes a new instance of the class.
/// The module file name.
///
/// If this number is positive, this is the index of the resource in the module file. If negative, the absolute value of the number
/// is the resource ID of the string in the module file.
///
public IndirectString(string module, int resourceIdOrIndex) : base(module, resourceIdOrIndex) { }
/// Gets the localized string referred to by this instance.
/// The referenced localized string.
[Browsable(false)]
public string? Value
{
get
{
if (RawValue is null) return null;
if (!IsValid) return RawValue;
var sb = new StringBuilder(4096);
SHLoadIndirectString(RawValue, sb, (uint)sb.Capacity).ThrowIfFailed();
return sb.ToString();
}
}
/// Performs an implicit conversion from to .
/// The ind.
/// The result of the conversion.
public static implicit operator string?(IndirectString? ind) => ind?.RawValue;
/// Performs an implicit conversion from to .
/// The s.
/// The result of the conversion.
public static implicit operator IndirectString(string? s) => new(s);
/// Tries to parse the specified string to create a instance.
/// The string representation in the format of either "ModuleFileName,ResourceIndex" or "ModuleFileName,-ResourceID".
/// The resulting instance on success.
/// true if successfully parsed.
public static bool TryParse(string? value, out IndirectString loc)
{
loc = new IndirectString(value);
return loc.IsValid || value != null;
}
[DllImport("shlwapi.dll", SetLastError = false, ExactSpelling = true)]
private static extern HRESULT SHLoadIndirectString([MarshalAs(UnmanagedType.LPWStr)] string pszSource,
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved = default);
}
internal class IndirectStringTypeConverter : ExpandableObjectConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) =>
sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destType) =>
destType == typeof(InstanceDescriptor) || destType == typeof(string) || base.CanConvertTo(context, destType);
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) =>
value is string s ? IndirectString.TryParse(s, out var loc) ? loc : null : base.ConvertFrom(context, culture, value);
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? info, object? value, Type destType)
{
if (destType == typeof(string) && value is IndirectString s)
return s.RawValue;
return destType == typeof(InstanceDescriptor)
? new InstanceDescriptor(typeof(IndirectString).GetConstructor(new Type[0]), null, false)
: base.ConvertTo(context, info, value, destType);
}
}
}