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