XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
using System.Runtime.InteropServices;
using XFEEliteDangerous.Client;

namespace XFEEliteDangerous.OfflineRuntime;

/// <summary>Settings and generated caches stay in the same owned profile across every launch.</summary>
internal static unsafe partial class OfflineProfileHooks
{
    private static ImportPointerHooks? imports;
    private static delegate* unmanaged<Guid*,uint,nint,nint*,int> originalKnownFolder;
    private static delegate* unmanaged<nint,int,nint,uint,char*,int> originalFolder;
    private static string local = "", roaming = "", saved = "";
    private static readonly Guid LocalId = new("F1B32785-6FBA-4FCF-9D55-7B8E7F157091");
    private static readonly Guid RoamingId = new("3EB685DB-65F9-4CF6-A03A-E3EF65729F3D");
    private static readonly Guid SavedId = new("4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4");
    internal static void Install(nint image, RuntimeConfiguration configuration)
    {
        local = Path.Combine(configuration.ProfileRoot, "LocalAppData");
        roaming = Path.Combine(configuration.ProfileRoot, "RoamingAppData"); saved = Path.Combine(configuration.ProfileRoot, "SavedGames");
        if (new[] {local,roaming,saved}.Any(path => !Directory.Exists(path) || path.Length >= 260)) throw new InvalidDataException("Persistent profile folders are absent or too long.");
        ConfigureRenderCache(Path.GetDirectoryName(configuration.Executable)!, configuration.ProfileRoot);
        var entry = image + 0x1F7730;
        if (!new ReadOnlySpan<byte>((void*)entry,32).SequenceEqual(Convert.FromHexString("48895c24085556574154415541564157488bec4883ec20b916000000e82f9b34")))
            throw new InvalidDataException("The pinned startup-only thread probe differs.");
        // The source-audited startup probe deliberately uses invalid handle 0xFFFF. Its
        // ordinary enum21 is only stored for diagnostics. No global NT API is changed.
        NativeHook.Write(entry, [0xB8,21,0,0,0,0xC3]);
        InstallDisplayDriverVersion(image, configuration.DriverVersion);
        imports = new ImportPointerHooks();
        var originals = imports.Install(image, new Dictionary<string,nint>
        {
            ["SHGetKnownFolderPath"] = (nint)(delegate* unmanaged<Guid*,uint,nint,nint*,int>)&KnownFolder,
            ["SHGetFolderPathW"] = (nint)(delegate* unmanaged<nint,int,nint,uint,char*,int>)&Folder,
            ["CreateFileW"] = (nint)(delegate* unmanaged<char*,uint,uint,nint,uint,uint,nint,nint>)&OpenWithRenderCache
        });
        originalKnownFolder = (delegate* unmanaged<Guid*,uint,nint,nint*,int>)originals["SHGetKnownFolderPath"];
        originalFolder = (delegate* unmanaged<nint,int,nint,uint,char*,int>)originals["SHGetFolderPathW"];
        originalCreateFile = (delegate* unmanaged<char*,uint,uint,nint,uint,uint,nint,nint>)originals["CreateFileW"];
    }
    [UnmanagedCallersOnly] private static int KnownFolder(Guid* id, uint flags, nint token, nint* output)
    {
        if (id == null || output == null) return unchecked((int)0x80070057);
        var path = *id == LocalId ? local : *id == RoamingId ? roaming : *id == SavedId ? saved : null;
        if (path is null) return originalKnownFolder(id, flags, token, output);
        try { *output = Marshal.StringToCoTaskMemUni(path); return 0; }
        catch(Exception error) { OfflineDiagnostics.Current?.Write("error","native.profile","folder.redirect.failed","Known-folder redirect failed.",exception:error);*output = 0; return unchecked((int)0x8007000e); }
    }
    [UnmanagedCallersOnly] private static int Folder(nint window, int csidl, nint token, uint flags, char* output)
    {
        var path = (csidl & 0xff) == 0x1c ? local : (csidl & 0xff) == 0x1a ? roaming : null;
        if (path is null) return originalFolder(window, csidl, token, flags, output);
        if (output == null) return unchecked((int)0x80070057);
        path.AsSpan().CopyTo(new Span<char>(output, 260)); output[path.Length] = '\0'; return 0;
    }
}