using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using Decal.Interop.Core; using Microsoft.Win32; namespace Decal.Core { [ComVisible(true)] [Guid("6DE65A82-C451-46E6-A82D-92137BE851AD")] [ClassInterface(ClassInterfaceType.None)] [ProgId("Decal.DecalEnum")] public class DecalEnumImpl : IDecalEnum { private class EnumEntry { public string FriendlyName = ""; public Guid ComClass; public bool Enabled = true; public bool Restricted; public Guid SurrogateClass; public string ResourcePath = ""; public string FilePath = ""; public string Version = ""; public int Order; } private readonly List _entries = new List(); private int _index = -1; private string _group = ""; private EnumEntry Current => (_index >= 0 && _index < _entries.Count) ? _entries[_index] : null; public string FriendlyName => Current?.FriendlyName ?? ""; public Guid ComClass => Current?.ComClass ?? Guid.Empty; public bool Enabled { get => Current?.Enabled ?? false; set { var c = Current; if (c == null) return; c.Enabled = value; try { using (var key = Registry.LocalMachine.OpenSubKey( $@"SOFTWARE\Decal\{_group}\{c.ComClass:B}", true)) { key?.SetValue("Enabled", value ? 1 : 0, RegistryValueKind.DWord); } } catch { } } } public bool Restricted => Current?.Restricted ?? false; public object CreateInstance(ref Guid riid) { var entry = Current; if (entry == null) return null; // If there's a surrogate, use it if (entry.SurrogateClass != Guid.Empty) { var surrogateType = Type.GetTypeFromCLSID(entry.SurrogateClass); if (surrogateType != null) { var surrogate = Activator.CreateInstance(surrogateType) as IDecalSurrogate; if (surrogate != null) return surrogate.CreateInstance((DecalEnum)(object)this, ref riid); } } // Direct COM creation var type = Type.GetTypeFromCLSID(entry.ComClass); return type != null ? Activator.CreateInstance(type) : null; } public void Next() { _index++; if (_index >= _entries.Count) Marshal.ThrowExceptionForHR(1); // S_FALSE } public Guid SurrogateClass => Current?.SurrogateClass ?? Guid.Empty; public string ResourcePath => Current?.ResourcePath ?? ""; public object Property => null; // Parameterized — returns registry values by name public string Group => _group; public void Skip(ref Guid clsid) { for (int i = 0; i < _entries.Count; i++) { if (_entries[i].ComClass == clsid) { _index = i; return; } } } public void MoveBefore(ref Guid clsidBefore) { if (_index < 0 || _index >= _entries.Count) return; var current = _entries[_index]; _entries.RemoveAt(_index); int targetIdx = _entries.Count; for (int i = 0; i < _entries.Count; i++) { if (_entries[i].ComClass == clsidBefore) { targetIdx = i; break; } } _entries.Insert(targetIdx, current); _index = targetIdx; } public string Version => Current?.Version ?? ""; public bool FileExists { get { var path = Current?.FilePath; return !string.IsNullOrEmpty(path) && File.Exists(path); } } public string FilePath => Current?.FilePath ?? ""; internal void Initialize(string group) { _group = group; _entries.Clear(); _index = -1; try { using (var baseKey = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Decal\{group}")) { if (baseKey == null) return; string orderStr = baseKey.GetValue("Order") as string ?? ""; foreach (string subKeyName in baseKey.GetSubKeyNames()) { if (!Guid.TryParse(subKeyName, out var clsid)) continue; using (var subKey = baseKey.OpenSubKey(subKeyName)) { if (subKey == null) continue; var entry = new EnumEntry { FriendlyName = subKey.GetValue(null) as string ?? subKeyName, ComClass = clsid, Enabled = ((int)(subKey.GetValue("Enabled") ?? 1)) != 0, Restricted = ((int)(subKey.GetValue("Restricted") ?? 0)) != 0, ResourcePath = subKey.GetValue("ResourcePath") as string ?? "", FilePath = subKey.GetValue("File") as string ?? "", Version = subKey.GetValue("Version") as string ?? "", }; var surrogateStr = subKey.GetValue("Surrogate") as string; if (!string.IsNullOrEmpty(surrogateStr) && Guid.TryParse(surrogateStr, out var surr)) entry.SurrogateClass = surr; var orderVal = subKey.GetValue("Order") as string; if (!string.IsNullOrEmpty(orderVal) && orderVal.Length > 0) { int pos = orderStr.IndexOf(orderVal[0]); entry.Order = pos >= 0 ? pos : int.MaxValue; } else { entry.Order = int.MaxValue; } _entries.Add(entry); } } } _entries.Sort((a, b) => a.Order.CompareTo(b.Order)); } catch { } } internal int Count => _entries.Count; } }