Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
d1442e3747
1382 changed files with 170725 additions and 0 deletions
199
Managed/Decal.Core/DecalEnumImpl.cs
Normal file
199
Managed/Decal.Core/DecalEnumImpl.cs
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
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<EnumEntry> _entries = new List<EnumEntry>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue