You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现C# COM Server类全局注册,实现C#与C++跨进程数据共享

解决方案:跨进程持久化注册状态(无需SQL等外部存储)

当前实现中RegisterPull.dictionary是进程内静态成员,进程退出后所有数据会被销毁,因此重启应用后IsRegister返回false。要实现应用重启后仍保留注册状态,且无需SQL等外部数据库,可借助Windows系统提供的跨进程存储机制,以下是两种可行方案:

方案1:内存映射文件(Memory-Mapped Files)

利用全局命名的内存映射文件存储注册数据,数据会被持久化到系统页文件,进程重启后可重新读取。

实现步骤:

  1. 标记ClientDetails为可序列化:
[Serializable]
public class ClientDetails
{
    public string Address { get; set; }
    public DateTime LastRegister { get; set; }
}
  1. 修改RegisterPull类,通过内存映射文件读写数据:
using System.IO.MemoryMappedFiles;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Collections.Concurrent;

public static class RegisterPull
{
    // 全局命名的内存映射文件和互斥锁,确保跨进程访问安全
    private const string _mapName = "Global_GameCheater_RegisterStore";
    private const int _mapSize = 1024 * 1024; // 分配1MB内存,可按需调整
    private static readonly Mutex _syncMutex = new Mutex(false, "Global_GameCheater_RegisterMutex");
    
    public static ConcurrentDictionary<string, ClientDetails> dictionary;

    static RegisterPull()
    {
        LoadDataFromMap();
    }

    private static void LoadDataFromMap()
    {
        _syncMutex.WaitOne();
        try
        {
            using var mmf = MemoryMappedFile.OpenOrCreate(_mapName, _mapSize);
            using var stream = mmf.CreateViewStream();
            
            var formatter = new BinaryFormatter();
            dictionary = stream.Length > 0 
                ? (ConcurrentDictionary<string, ClientDetails>)formatter.Deserialize(stream) 
                : new ConcurrentDictionary<string, ClientDetails>();
        }
        finally
        {
            _syncMutex.ReleaseMutex();
        }
    }

    public static void SaveDataToMap()
    {
        _syncMutex.WaitOne();
        try
        {
            using var mmf = MemoryMappedFile.OpenOrCreate(_mapName, _mapSize);
            using var stream = mmf.CreateViewStream();
            
            stream.SetLength(0); // 清空旧数据
            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, dictionary);
        }
        finally
        {
            _syncMutex.ReleaseMutex();
        }
    }
}
  1. 更新RegisterManager的Register方法,每次修改后保存数据:
public void Register(string address)
{
    var clientDetails = new ClientDetails()
    {
        Address = address,
        LastRegister = DateTime.Now
    };

    if (RegisterPull.dictionary.ContainsKey(address))
        RegisterPull.dictionary[address] = clientDetails;
    else
        RegisterPull.dictionary.TryAdd(address, clientDetails);
    
    RegisterPull.SaveDataToMap(); // 同步到内存映射文件
}

注意事项:

  • 全局命名(前缀Global\)需要管理员权限,若仅需同一会话内进程共享,可去掉前缀使用本地命名。
  • 若注册数据量大,建议更换更高效的序列化方式(如Protobuf)替代BinaryFormatter,同时调整内存映射文件大小。
  • 系统重启后,内存映射文件数据会丢失,若需系统重启后仍保留,可结合方案2。

方案2:Windows注册表

将注册信息写入Windows注册表,进程重启时从注册表读取,无需额外存储文件。

实现步骤:

  1. 修改RegisterPull类,通过注册表读写数据:
using Microsoft.Win32;
using System.Collections.Concurrent;

public static class RegisterPull
{
    private const string _regPath = @"Software\GameCheater\RegisterRecords";
    public static ConcurrentDictionary<string, ClientDetails> dictionary;

    static RegisterPull()
    {
        LoadDataFromRegistry();
    }

    private static void LoadDataFromRegistry()
    {
        dictionary = new ConcurrentDictionary<string, ClientDetails>();
        using var key = Registry.CurrentUser.OpenSubKey(_regPath);
        if (key == null) return;

        foreach (var address in key.GetValueNames())
        {
            var lastRegisterStr = key.GetValue(address) as string;
            if (DateTime.TryParse(lastRegisterStr, out var lastRegister))
            {
                dictionary.TryAdd(address, new ClientDetails { Address = address, LastRegister = lastRegister });
            }
        }
    }

    public static void SaveDataToRegistry()
    {
        using var key = Registry.CurrentUser.CreateSubKey(_regPath);
        foreach (var kvp in dictionary)
        {
            key.SetValue(kvp.Key, kvp.Value.LastRegister.ToString("o")); // 用ISO格式存储时间
        }
    }
}
  1. 更新RegisterManager的Register方法:
public void Register(string address)
{
    var clientDetails = new ClientDetails()
    {
        Address = address,
        LastRegister = DateTime.Now
    };

    if (RegisterPull.dictionary.ContainsKey(address))
        RegisterPull.dictionary[address] = clientDetails;
    else
        RegisterPull.dictionary.TryAdd(address, clientDetails);
    
    RegisterPull.SaveDataToRegistry(); // 同步到注册表
}

注意事项:

  • 注册表操作需要对应权限,HKEY_CURRENT_USER路径下的操作无需管理员权限。
  • 存储数据格式需统一,避免解析失败。

结论

两种方案均无需使用SQL等外部数据库,可实现应用重启后保留注册状态,C++通过COM调用RegisterManager的IsRegister和Register方法即可正常获取/修改注册结果。

内容的提问来源于stack exchange,提问作者Alex Soryn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 05:12:16