From e57938fbda9bff702004038f76d009422968bff5 Mon Sep 17 00:00:00 2001
From: alielie <alielie@git.com>
Date: 星期五, 06 十一月 2026 18:05:07 +0800
Subject: [PATCH] 提交代码

---
 DeviceService/DriverManager/DriverManager.cs |  411 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 411 insertions(+), 0 deletions(-)

diff --git a/DeviceService/DriverManager/DriverManager.cs b/DeviceService/DriverManager/DriverManager.cs
new file mode 100644
index 0000000..242ac4f
--- /dev/null
+++ b/DeviceService/DriverManager/DriverManager.cs
@@ -0,0 +1,411 @@
+using System.IO;
+
+namespace DeviceService.Driver
+{
+    /// <summary>
+    /// 涓�涓凡闅旂鍔犺浇鐨勯┍鍔ㄥ寘锛堝搴旈┍鍔ㄦ牴鐩綍涓嬬殑涓�涓瓙鏂囦欢澶癸級銆�
+    /// </summary>
+    public sealed class DriverPackage
+    {
+        /// <summary>瀛愭枃浠跺す鍚嶏紙閫氬父涓哄巶鍟�/璁惧鍚嶏級</summary>
+        public string Folder { get; set; }
+
+        /// <summary>椹卞姩鍖呮墍鍦ㄧ墿鐞嗙洰褰�</summary>
+        public string Directory { get; set; }
+
+        /// <summary>椹卞姩鍖呬笓灞� AppDomain</summary>
+        public AppDomain Domain { get; set; }
+
+        /// <summary>杩愯鍦ㄨ鍩熷唴鐨勫姞杞藉櫒浠g悊</summary>
+        public DriverLoader Loader { get; set; }
+
+        /// <summary>璇ュ寘鍐呯殑绋嬪簭闆嗕笌鍏紑绫诲瀷</summary>
+        public DriverAssemblyInfo[] Assemblies { get; set; }
+    }
+
+    /// <summary>
+    /// (绫诲瀷, 鍝佺墝) 鏌ユ壘缁撴灉銆�
+    /// </summary>
+    public sealed class DriverFindResult
+    {
+        public DriverPackage Package { get; set; }
+        public DriverTypeInfo Info { get; set; }
+    }
+
+    /// <summary>
+    /// 椹卞姩绠$悊鍣細鎵弿鏍圭洰褰曚笅鎵�鏈夊瓙鏂囦欢澶癸紝姣忎釜瀛愭枃浠跺す涓�涓殧绂诲煙銆�
+    ///
+    /// 閫傜敤浜�"涓嶅悓鍘傚晢鎻愪緵鐨勯┍鍔� dll 涔嬮棿娌℃湁浠讳綍濂戠害"鐨勫満鏅細
+    /// - 椹卞姩 dll 涓嶉渶瑕佸疄鐜版帴鍙c�佷笉闇�瑕佸紩鐢ㄥ涓荤▼搴忛泦锛�
+    /// - 瀹夸富鍙�氳繃鍙嶅皠鏋氫妇绫诲瀷/鏂规硶銆佸垱寤哄疄渚嬨�佽皟鐢ㄦ柟娉曪紱
+    /// - 姣忎釜椹卞姩鍖呰嚜甯﹁嚜宸辩殑渚濊禆锛屼簰涓嶅共鎵帮紙鍙瓨鍦ㄥ悓鍚嶄笉鍚岀増鏈級锛�
+    /// - 闇�瑕佹浛鎹㈤┍鍔ㄦ枃浠舵椂鍏堝嵏杞藉煙锛屾枃浠朵笉浼氳閿佸畾锛堝奖瀛愬鍒讹級銆�
+    /// </summary>
+    public sealed class DriverManager
+    {
+        private static DriverManager _instance;
+
+        public static DriverManager Instance
+        {
+            get
+            {
+                if (_instance == null)
+                {
+                    _instance = new DriverManager();
+                }
+                return _instance;
+            }
+        }
+
+        private DriverManager()
+        {
+        }
+
+        private readonly List<DriverPackage> _packages = new List<DriverPackage>();
+
+        /// <summary>鐢� DriverManager 缁熶竴鐧昏绠$悊鐨勯┍鍔ㄥ疄渚嬶紙璺ㄥ煙閫忔槑浠g悊锛�</summary>
+        private readonly Dictionary<string, DriverInstance> _managedDrivers =
+            new Dictionary<string, DriverInstance>(StringComparer.Ordinal);
+
+        public IReadOnlyList<DriverPackage> Packages => _packages;
+
+        /// <summary>褰撳墠鐢� DriverManager 绠$悊鐨勫叏閮ㄩ┍鍔ㄥ疄渚�</summary>
+        public IReadOnlyCollection<DriverInstance> ManagedDrivers => _managedDrivers.Values;
+
+        /// <summary>
+        /// 鎵弿 rootPath 涓嬬殑姣忎釜瀛愭枃浠跺す骞跺垱寤洪殧绂诲煙鍔犺浇銆�
+        /// </summary>
+        public void Scan(string rootPath, Action<string> log)
+        {
+            if (!Directory.Exists(rootPath))
+            {
+                log?.Invoke($"[閿欒] 鐩綍涓嶅瓨鍦�: {rootPath}");
+                return;
+            }
+
+            var subDirs = Directory.GetDirectories(rootPath);
+            if (subDirs.Length == 0)
+            {
+                log?.Invoke($"[鎻愮ず] {rootPath} 涓嬫病鏈夊瓙鏂囦欢澶癸紙姣忎釜瀛愭枃浠跺す搴斾负涓�涓┍鍔ㄥ寘锛�");
+                return;
+            }
+
+            foreach (var dir in subDirs)
+            {
+                var brandDirs = Directory.GetDirectories(dir);
+
+                foreach (var brandDir in brandDirs)
+                {
+                    var name = Path.GetFileName(brandDir);
+
+                    try
+                    {
+                        LoadPackage(brandDir, name, log);
+                    }
+                    catch (Exception ex)
+                    {
+                        log?.Invoke($"[澶辫触] {name}: {ex.Message}");
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 鍒楀嚭鏌愪釜绫诲瀷鍙皟鐢ㄧ殑鍏叡鏂规硶銆�
+        /// </summary>
+        public DriverMethodInfo[] GetMethods(DriverPackage package, string typeFullName)
+        {
+            return package.Loader.GetMethods(typeFullName);
+        }
+
+        /// <summary>
+        /// 鍦ㄦ墍鏈夊凡鍔犺浇椹卞姩鍖呬腑鎸� (绫诲瀷, 鍝佺墝) 鏌ユ壘椹卞姩銆�
+        /// 浠讳竴瀛楁鐣欑┖瑙嗕负閫氶厤锛涘悓涓�缁勫悎鍛戒腑澶氫釜鍖呮椂璁板綍璀﹀憡骞惰繑鍥炵涓�涓��
+        /// </summary>
+        public DriverFindResult FindDriver(string driverType, string brand, Action<string> log)
+        {
+            DriverFindResult first = null;
+
+            foreach (var package in _packages)
+            {
+                var info = package.Loader.FindDriver(driverType, brand);
+                if (info == null)
+                {
+                    continue;
+                }
+
+                if (first == null)
+                {
+                    first = new DriverFindResult { Package = package, Info = info };
+                }
+                else
+                {
+                    log?.Invoke($"[璀﹀憡] (绫诲瀷={driverType}, 鍝佺墝={brand}) 鍦ㄥ涓┍鍔ㄥ寘涓噸澶�: "
+                                + $"{first.Package.Folder} 涓� {package.Folder}锛岃繑鍥炵涓�涓�");
+                }
+            }
+
+            return first;
+        }
+
+        /// <summary>
+        /// 鍙嶅皠璋冪敤椹卞姩鏂规硶锛堝疄闄呮墽琛屽彂鐢熷湪璇ラ┍鍔ㄨ嚜宸辩殑鍩熷唴锛夈��
+        /// </summary>
+        public InvokeResult Invoke(DriverPackage package, string typeFullName, int methodIndex, string[] args)
+        {
+            return package.Loader.Invoke(typeFullName, methodIndex, args);
+        }
+
+        /// <summary>
+        /// 鏍规嵁 (绫诲瀷, 鍝佺墝) 鎵惧埌瀵瑰簲鐨勯┍鍔ㄧ被鍨嬶紝鍦ㄥ叾鎵�灞為┍鍔ㄥ寘鐨� AppDomain 鍐�
+        /// 鍒涘缓涓�涓柊瀹炰緥骞朵互閫忔槑浠g悊褰㈠紡杩斿洖锛岀敱 DriverManager 缁熶竴鐧昏绠$悊銆�
+        ///
+        /// 璇存槑锛氶┍鍔ㄧ被鍨嬫湰韬笉鍙法鍩熷皝閫侊紙闈� MarshalByRefObject锛屽涓讳篃涓嶅紩鐢ㄥ巶鍟嗙▼搴忛泦锛夛紝
+        /// 鍥犳鏃犳硶鐢ㄦ硾鍨� T 杩斿洖"鍘熺敓绫诲瀷"锛涘涓讳竴寰嬮�氳繃 <see cref="DriverInstance"/> 浠g悊鎿嶄綔锛�
+        /// 姣忔璋冪敤瀹為檯鎵ц鍙戠敓鍦ㄩ┍鍔ㄨ嚜宸辩殑鍩熷唴銆�
+        /// </summary>
+        /// <param name="driverType">娉ㄨВ涓殑"绫诲瀷"锛屽 CAN锛涚暀绌轰负閫氶厤</param>
+        /// <param name="brand">娉ㄨВ涓殑"鍝佺墝"锛屽 BA锛涚暀绌轰负閫氶厤</param>
+        /// <param name="log">鏃ュ織鍥炶皟锛堝彲绌猴級</param>
+        /// <returns>椹卞姩瀹炰緥浠g悊锛涙湭鎵惧埌鎴栧垱寤哄け璐ヨ繑鍥� null</returns>
+        public DriverInstance CreateDriverByTypeAndBrand(string driverType, string brand, Action<string> log = null)
+        {
+            var hit = FindDriver(driverType, brand, log);
+            if (hit == null)
+            {
+                log?.Invoke($"[鍒涘缓] 鏈壘鍒� (绫诲瀷={driverType}, 鍝佺墝={brand}) 瀵瑰簲鐨勯┍鍔�");
+                return null;
+            }
+
+            try
+            {
+                var instance = hit.Package.Loader.CreateInstance(hit.Info.FullName, hit.Info.DriverType, hit.Info.Brand);
+                instance.PackageFolder = hit.Package.Folder;
+                _managedDrivers[instance.Handle] = instance;
+
+                log?.Invoke($"[鍒涘缓] {hit.Info.FullName}锛坽hit.Info.DriverType}/{hit.Info.Brand}锛屽寘 {hit.Package.Folder}锛�"
+                            + $" => 瀹炰緥 {ShortHandle(instance.Handle)}");
+                return instance;
+            }
+            catch (Exception ex)
+            {
+                log?.Invoke($"[鍒涘缓澶辫触] {hit.Info.FullName}: {ex.Message}");
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 娉涘瀷鐗堟湰锛歍 涓哄涓昏嚜瀹氫箟鐨�"楦瓙鎺ュ彛"锛堟柟娉曞悕銆佸弬鏁扮被鍨嬩笌椹卞姩鏂规硶涓�涓�瀵瑰簲锛夈��
+        /// 杩斿洖 DispatchProxy 鍔ㄦ�佷唬鐞嗭細鎺ュ彛璋冪敤鎸�"鏂规硶鍚� + 鍙傛暟涓暟"杞彂鍒伴┍鍔ㄥ煙鍐呭弽灏勬墽琛屻��
+        ///
+        /// 椹卞姩鏃犻渶瀹炵幇 T銆佹棤闇�寮曠敤瀹夸富绋嬪簭闆嗏�斺�旇繖姝f槸鍔ㄦ�佷唬鐞嗙殑鎰忎箟锛�
+        /// 涓嶅悓鍘傚晢鐨勯┍鍔ㄥ彲浠ュ叡浜涓诲畾涔夌殑涓�濂楁帴鍙g害瀹氥��
+        ///
+        /// 绾︽潫锛�
+        /// - T 蹇呴』鏄帴鍙o紙DispatchProxy 鍙拡瀵规帴鍙g敓鎴愪唬鐞嗙被锛夛紱
+        /// - 鎺ュ彛鏂规硶鐨勫弬鏁�/杩斿洖鍊煎繀椤诲彲璺ㄥ煙灏侀�侊紙鍩哄厓绫诲瀷銆乻tring銆乕Serializable] DTO锛夛紱
+        /// - 姣忔璋冪敤閮芥槸涓�娆¤法鍩熷弽灏勶紝鎬ц兘浣庝簬鐩存帴璋冪敤锛岄�傚悎璁惧鎺у埗绫讳綆棰戞搷浣溿��
+        /// </summary>
+        public T CreateDriverByTypeAndBrand<T>(string driverType, string brand, Action<string> log = null)
+            where T : class
+        {
+            var instance = CreateDriverByTypeAndBrand(driverType, brand, log);
+            if (instance == null)
+            {
+                return null;
+            }
+
+            log?.Invoke($"[浠g悊] {instance.TypeFullName} => {typeof(T).Name} 鍔ㄦ�佷唬鐞嗭紙瀹炰緥 {ShortHandle(instance.Handle)}锛�");
+            return DriverDispatchProxy.Create<T>(instance);
+        }
+
+        /// <summary>
+        /// 閲婃斁涓�涓敱 DriverManager 绠$悊鐨勯┍鍔ㄥ疄渚嬶紙椹卞姩瀹炵幇 IDisposable 鏃朵細璋冪敤 Dispose锛夈��
+        /// </summary>
+        public void ReleaseDriver(DriverInstance instance, Action<string> log = null)
+        {
+            if (instance == null)
+            {
+                return;
+            }
+
+            _managedDrivers.Remove(instance.Handle);
+            try
+            {
+                instance.Release();
+                log?.Invoke($"[閲婃斁] 瀹炰緥 {ShortHandle(instance.Handle)}锛坽instance.TypeFullName}锛�");
+            }
+            catch (Exception ex)
+            {
+                log?.Invoke($"[閲婃斁澶辫触] 瀹炰緥 {ShortHandle(instance.Handle)}: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 鍗歌浇鏌愪釜椹卞姩鍖呭墠锛屽厛閫氳繃浠g悊閲婃斁鍏跺悕涓嬫墍鏈夋墭绠″疄渚嬶紙鍩熷嵏杞藉悗浠g悊浼氬け鏁堬級銆�
+        /// </summary>
+        private void ReleaseInstancesOf(DriverPackage package, Action<string> log)
+        {
+            var targets = _managedDrivers.Values
+                .Where(i => i.PackageFolder == package.Folder)
+                .ToList();
+
+            foreach (var instance in targets)
+            {
+                ReleaseDriver(instance, log);
+            }
+        }
+
+        private static string ShortHandle(string handle) => handle.Substring(0, Math.Min(8, handle.Length));
+
+        /// <summary>
+        /// 鍗歌浇鎵�鏈夐┍鍔ㄥ煙锛堥噴鏀剧▼搴忛泦銆佽В閿� dll 鏂囦欢锛夈��
+        /// </summary>
+        public void UnloadAll(Action<string> log)
+        {
+            // 鍏堥�氳繃浠g悊閲婃斁鎵�鏈夋墭绠″疄渚嬶紝鍩熷嵏杞藉悗浠g悊灏嗗け鏁�
+            foreach (var instance in _managedDrivers.Values.ToList())
+            {
+                ReleaseDriver(instance, log);
+            }
+
+            var domains = _packages.Select(p => p.Domain).Distinct().ToList();
+            _packages.Clear();
+
+            foreach (var domain in domains)
+            {
+                // 娉ㄦ剰锛氬繀椤诲湪鍗歌浇鍓嶈鍙� FriendlyName锛屽煙鍗歌浇鍚庡啀璁块棶鍏跺睘鎬т細鎶� AppDomainUnloadedException
+                var name = domain.FriendlyName;
+                try
+                {
+                    AppDomain.Unload(domain);
+                    log?.Invoke($"[鍗歌浇] {name}");
+                }
+                catch (Exception ex)
+                {
+                    log?.Invoke($"[鍗歌浇澶辫触] {name}: {ex.Message}");
+                }
+            }
+        }
+
+        private DriverPackage LoadPackage(string dir, string name, Action<string> log)
+        {
+            // 鍔犺浇鍣ㄤ笌 DTO 濂戠害缁熶竴浣跨敤瀹夸富鐩綍涓殑鍞竴鍓湰锛屼笉鍐嶅悜椹卞姩鐩綍澶嶅埗
+            var loaderPath = typeof(DriverLoader).Assembly.Location;
+            WarnIfStaleRuntimeFiles(dir, name, log);
+
+            var setup = new AppDomainSetup
+            {
+                ApplicationName = name,
+                // 鍏抽敭锛氭帰娴嬫牴鍥哄畾涓鸿椹卞姩鐩綍锛屼緷璧栧彧浼氫粠鑷繁鐩綍瑙f瀽
+                ApplicationBase = dir,
+                // 褰卞瓙澶嶅埗锛歞ll 鍔犺浇鍚庝笉閿佸畾锛屽彲闅忔椂鍗歌浇/鏇挎崲鏂囦欢
+                ShadowCopyFiles = "true",
+                ShadowCopyDirectories = dir,
+                CachePath = Path.Combine(Path.GetTempPath(), "MultiPluginCache", name)
+            };
+
+            var domain = AppDomain.CreateDomain("Driver_" + name, null, setup);
+            try
+            {
+                var loader = (DriverLoader)domain.CreateInstanceFromAndUnwrap(loaderPath, typeof(DriverLoader).FullName);
+
+                var assemblies = loader.LoadAssemblies();
+                var package = new DriverPackage
+                {
+                    Folder = name,
+                    Directory = dir,
+                    Domain = domain,
+                    Loader = loader,
+                    Assemblies = assemblies
+                };
+                _packages.Add(package);
+
+                // 椹卞姩淇℃伅鎸佷箙鍖栧埌 Config\Drivers.db
+                DriverDatabase.Instance.SavePackage(package, log);
+
+                var totalDrivers = assemblies.Where(a => a.Types != null).Sum(a => a.Types.Length);
+                var failed = assemblies.Count(a => a.Error != null);
+                log?.Invoke($"[椹卞姩鍖匽 {name}: {assemblies.Length} 涓� dll锛寋totalDrivers} 涓┍鍔ㄧ被鍨�"
+                            + (failed > 0 ? $"锛寋failed} 涓棤娉曞姞杞�" : string.Empty));
+
+                foreach (var asm in assemblies.Where(a => a.Error != null))
+                {
+                    log?.Invoke($"    [!] {asm.FileName}: {asm.Error}");
+                }
+
+                return package;
+            }
+            catch
+            {
+                try { AppDomain.Unload(domain); } catch { /* 蹇界暐 */ }
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// 鍗歌浇鎸囧畾鐨勯┍鍔ㄥ寘锛堥噴鏀捐鍩熶腑鐨勬墍鏈夌▼搴忛泦锛夈��
+        /// </summary>
+        public void Unload(DriverPackage package, Action<string> log)
+        {
+            // 鍩熷嵏杞藉墠鍏堥噴鏀捐鍖呭悕涓嬬殑鎵樼瀹炰緥锛岄伩鍏嶆搷浣滃け鏁堜唬鐞�
+            ReleaseInstancesOf(package, log);
+
+            _packages.Remove(package);
+
+            // 鍚屾绉婚櫎璇ラ┍鍔ㄥ寘鍦� Config\Drivers.db 涓殑璁板綍
+            DriverDatabase.Instance.RemovePackage(package.Folder, log);
+
+            try
+            {
+                AppDomain.Unload(package.Domain);
+                log?.Invoke($"[鍗歌浇] {package.Folder}");
+            }
+            catch (Exception ex)
+            {
+                log?.Invoke($"[鍗歌浇澶辫触] {package.Folder}: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 閲嶈浇鎸囧畾鐨勯┍鍔ㄥ寘锛氬嵏杞芥棫鍩熷悗鐢ㄥ悓涓�鐩綍閲嶆柊鍒涘缓鍩熴��
+        /// 渚濊禆褰卞瓙澶嶅埗锛屾浛鎹� dll 鍚庢棤闇�閲嶅惎瀹夸富鍗冲彲鐢熸晥銆�
+        /// </summary>
+        public DriverPackage Reload(DriverPackage package, Action<string> log)
+        {
+            var dir = package.Directory;
+            var name = package.Folder;
+
+            Unload(package, log);
+            log?.Invoke($"[閲嶈浇] {name} ...");
+
+            return LoadPackage(dir, name, log);
+        }
+
+        /// <summary>
+        /// 鏃╂湡鐗堟湰浼氭妸鍔犺浇鍣�/DTO 澶嶅埗鍒版瘡涓┍鍔ㄧ洰褰曪紝姝ゅ娓呯悊娈嬬暀锛岄伩鍏嶆棫鐗堟湰 Contracts 骞叉壈銆�
+        /// 椹卞姩鐩綍鏈韩涓嶉渶瑕併�佷篃涓嶅簲璇ュ寘鍚涓昏繍琛屾椂鏂囦欢銆�
+        /// </summary>
+        private static void WarnIfStaleRuntimeFiles(string dir, string name, Action<string> log)
+        {
+            foreach (var fileName in new[] { "MultiPlugin.Loader.dll", "MultiPlugin.Contracts.dll" })
+            {
+                var path = Path.Combine(dir, fileName);
+                if (!File.Exists(path))
+                {
+                    continue;
+                }
+
+                try
+                {
+                    File.Delete(path);
+                    log?.Invoke($"[娓呯悊] {name}: 宸插垹闄ゅ浣欑殑 {fileName}锛堣繍琛屾椂缁熶竴浣跨敤瀹夸富鐩綍鐗堟湰锛�");
+                }
+                catch (Exception ex)
+                {
+                    log?.Invoke($"[鎻愮ず] {name}: 瀛樺湪澶氫綑鐨� {fileName}锛屽凡蹇界暐锛坽ex.Message}锛�");
+                }
+            }
+        }
+    }
+}

--
Gitblit v1.9.1