#if SYSLINKGETSWORKING using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using Vanara.Extensions; using Vanara.InteropServices; using static Vanara.PInvoke.ComCtl32; using static Vanara.PInvoke.User32; namespace Vanara.PInvoke.Controls; /// Represents a Windows SysLink control that displays one or more hyperlinks. /// public class SysLink : Control { private static readonly bool IsPlatformSupported = Environment.OSVersion.Version.Major > 5; private static Lazy init = new(() => InitCommonControlsEx(CommonControlClass.ICC_LINK_CLASS)); /// Initializes a new instance of the class. public SysLink() { if (!IsPlatformSupported) throw new InvalidOperationException("A SysLink control is only supported after Vista."); if (!init.Value) throw new InvalidOperationException("Failed to initialize common controls."); Items = new(this); } /// Gets the list of hyperlinks. /// The hyperlinks. public SysLinkItemList Items { get; } /// protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ClassName = WC_LINK; cp.Caption = "Click here"; return cp; } } /// protected override Size DefaultSize => new(200, AutoSize ? PreferredSize.Height : 58); /// public override Size GetPreferredSize(Size proposedSize) { SIZE sz = proposedSize; if (IsHandleCreated) { using PinnedObject psz = new(sz); var h = SendMessage(Handle, SysLinkMessage.LM_GETIDEALSIZE, proposedSize.Width, psz).ToInt32(); } return sz; } } /// Exposes the list of hyperlinks in a control. This class cannot be inherited. public sealed class SysLinkItemList : IReadOnlyList { private readonly SysLink parent; internal SysLinkItemList(SysLink parent) => this.parent = parent; /// public int Count { get { int count = 0; for (IEnumerator e = GetEnumerator(); e.MoveNext(); count++) ; return Count; } } /// public SysLinkItem this[int index] => new((HWND)parent.Handle, ValidateIndex(index)); /// public IEnumerator GetEnumerator() { LITEM li = new(0, LIF.LIF_STATE); using var pli = new PinnedObject(li); if (parent.IsHandleCreated) for (; li.iLink < ushort.MaxValue && IntPtr.Zero != SendMessage(parent.Handle, SysLinkMessage.LM_GETITEM, default, pli); li.iLink++) yield return new((HWND)parent.Handle, li.iLink); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private int ValidateIndex(int index) { LITEM li = new(index, LIF.LIF_STATE); using var pli = new PinnedObject(li); return IntPtr.Zero == SendMessage(parent.Handle, SysLinkMessage.LM_GETITEM, default, pli) ? throw new ArgumentOutOfRangeException(nameof(index)) : index; } } /// Information about a hyperlink exposed by a control. This class cannot be inherited. public sealed class SysLinkItem { private readonly int index; private readonly HWND parent; internal SysLinkItem(HWND handle, int index) { parent = handle; this.index = index; } /// Gets or sets a value indicating whether this is enabled. /// if enabled; otherwise, . public bool Enabled { get => GetState(LIS.LIS_ENABLED); set => SetState(LIS.LIS_ENABLED, value); } /// Gets or sets a value indicating whether this is focused. /// if focused; otherwise, . public bool Focused { get => GetState(LIS.LIS_FOCUSED); set => SetState(LIS.LIS_FOCUSED, value); } /// Gets or sets a value indicating whether this is hover. /// if hover; otherwise, . public bool Hover { get => GetState(LIS.LIS_HOTTRACK); set => SetState(LIS.LIS_HOTTRACK, value); } /// Gets or sets the key. /// The key. public string Key { get => GetInfo(LIF.LIF_ITEMID).szID ?? index.ToString(); set => SetInfo(new(index, LIF.LIF_ITEMID) { szID = value }); } /// Gets or sets the URL. /// The URL. public Uri Url { get => new(GetInfo(LIF.LIF_URL).szUrl); set => SetInfo(new(index, LIF.LIF_URL) { szUrl = value.AbsoluteUri }); } /// Gets or sets a value indicating whether this is visited. /// if visited; otherwise, . public bool Visited { get => GetState(LIS.LIS_VISITED); set => SetState(LIS.LIS_VISITED, value); } private LITEM GetInfo(LIF mask) { LITEM li = new(index, mask); using PinnedObject pli = new(li); if (mask.IsFlagSet(LIF.LIF_STATE)) li.stateMask = (LIS)0x1f; SendMessage(parent, SysLinkMessage.LM_GETITEM, default, pli); return li; } private bool GetState(LIS mask) => GetInfo(LIF.LIF_STATE).state.IsFlagSet(mask); private void SetInfo(in LITEM item) { using PinnedObject pli = new(item); if (0 != SendMessage(parent, SysLinkMessage.LM_SETITEM, default, pli).ToInt32()) Win32Error.ThrowLastError(); } private void SetState(LIS lIS, bool value) => SetInfo(new(index, LIF.LIF_STATE) { stateMask = lIS, state = value ? lIS : 0 }); } #endif