using System.IO;
using System.Reflection;
namespace DeviceService.Driver
{
///
/// 驱动的程序集描述(跨 AppDomain 按值封送)。
/// 注意:这些 DTO 只服务于"宿主 <-> 加载器"之间的通信,
/// 驱动 dll 不需要引用本程序集,也不需要实现任何接口。
///
[Serializable]
public sealed class DriverAssemblyInfo
{
/// dll 文件名
public string FileName { get; set; }
/// 程序集完整标识(加载成功时)
public string AssemblyFullName { get; set; }
/// 加载失败原因(成功时为 null)
public string Error { get; set; }
/// 带 [DriverDesc] 注解的驱动类型(按类型名排序)
public DriverTypeInfo[] Types { get; set; }
}
///
/// 一个驱动类型的描述信息(来自 DriverDescAttribute)。
/// 通过 (类型, 品牌) 可唯一定位到该类型。
///
[Serializable]
public sealed class DriverTypeInfo
{
/// CLR 类型全名
public string FullName { get; set; }
/// 注解中的"类型"(如 CAN、串口)
public string DriverType { get; set; }
/// 注解中的"品牌"(如 BA、BB)
public string Brand { get; set; }
}
///
/// 驱动类型上的一个公共方法。
///
[Serializable]
public sealed class DriverMethodInfo
{
/// 方法在该类型方法表中的索引(调用时回传)
public int Index { get; set; }
public string Name { get; set; }
/// 可读签名,例如 int ReadStatus(int channel)
public string Signature { get; set; }
public bool IsStatic { get; set; }
public int ParameterCount { get; set; }
/// 参数列表(类型名 + 参数名),用于界面提示
public string[] Parameters { get; set; }
}
///
/// 反射调用结果。
///
[Serializable]
public sealed class InvokeResult
{
public bool Success { get; set; }
/// 返回值文本(成功时)
public string Output { get; set; }
/// 错误信息(失败时)
public string Error { get; set; }
}
///
/// 直接调用结果:保留原始返回值与 out/ref 回填值,
/// 供 RealProxy 动态代理把驱动调用适配成强类型接口方法。
/// 注意:Value / ArgsOut 只能携带可跨域封送的数据(基元类型、string、[Serializable] DTO)。
///
[Serializable]
public sealed class InvokeDirectResult
{
public bool Success { get; set; }
/// 方法返回值(void 方法为 null)
public object Value { get; set; }
/// 调用后的参数数组(out/ref 位置为回填值,其余位置原值)
public object[] ArgsOut { get; set; }
/// 错误信息(失败时)
public string Error { get; set; }
}
///
/// 运行在每个驱动包专属 AppDomain 内的加载器。
///
/// 设计前提:驱动 dll 来自不同厂商,彼此没有任何共同接口/基类约定,
/// 甚至互不兼容(同一第三方依赖的不同版本)。
/// 因此这里只做通用反射:枚举公开类型、枚举公共方法、反射创建实例、反射调用。
///
/// 该域的 ApplicationBase 被设置为某个驱动子文件夹,
/// 所以驱动的全部依赖只能从自己目录解析,天然隔离版本冲突。
///
public class DriverLoader : MarshalByRefObject
{
private static readonly HashSet FailedAssemblies =
new HashSet(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary _types = new Dictionary(StringComparer.Ordinal);
private readonly Dictionary _methodCache = new Dictionary(StringComparer.Ordinal);
private readonly Dictionary _instances = new Dictionary();
/// 由 DriverManager 创建、按句柄管理的驱动实例
private readonly Dictionary _managedInstances =
new Dictionary(StringComparer.Ordinal);
/// 驱动索引:(类型, 品牌) → 驱动信息,key 形如 "CAN|BA"
private readonly Dictionary _driverIndex =
new Dictionary(StringComparer.OrdinalIgnoreCase);
// 无限生存期,避免远程代理被回收
public override object InitializeLifetimeService() => null;
public DriverLoader()
{
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
}
#region 发现
///
/// 扫描本驱动目录下的所有 dll(忽略宿主自身的 MultiPlugin.* 运行时文件),
/// 返回每个程序集的信息与公开类型列表。
///
public DriverAssemblyInfo[] LoadAssemblies()
{
var dir = AppDomain.CurrentDomain.BaseDirectory;
var result = new List();
foreach (var path in Directory.GetFiles(dir, "*.dll").OrderBy(p => p, StringComparer.OrdinalIgnoreCase))
{
var fileName = Path.GetFileName(path);
if (fileName.StartsWith("MultiPlugin.", StringComparison.OrdinalIgnoreCase))
{
continue; // 宿主基础设施,非驱动
}
var info = new DriverAssemblyInfo { FileName = fileName };
try
{
var assembly = Assembly.Load(Path.GetFileNameWithoutExtension(path));
info.AssemblyFullName = assembly.FullName;
// 只收录带 [DriverDesc] 注解的类,其余类型一律忽略
var drivers = new List();
foreach (var type in assembly.GetExportedTypes())
{
if (!type.IsClass || type.IsAbstract)
{
continue;
}
var desc = ReadDriverDesc(type);
if (desc == null)
{
continue;
}
_types[type.FullName] = type;
var driverInfo = new DriverTypeInfo
{
FullName = type.FullName,
DriverType = desc.Item1,
Brand = desc.Item2
};
drivers.Add(driverInfo);
_driverIndex[DriverKey(desc.Item1, desc.Item2)] = driverInfo;
}
info.Types = drivers.OrderBy(t => t.FullName, StringComparer.Ordinal).ToArray();
}
catch (Exception ex)
{
// 非托管 dll、缺少依赖、架构不匹配等都会到这里
info.Error = ex.Message;
}
result.Add(info);
}
return result.ToArray();
}
///
/// 按 (类型, 品牌) 查找驱动。任一字段留空视为通配。
///
/// 命中的第一个驱动信息;未命中返回 null
public DriverTypeInfo FindDriver(string driverType, string brand)
{
var key = DriverKey(driverType, brand);
if (_driverIndex.TryGetValue(key, out var exact))
{
return exact;
}
// 精确未命中且存在通配字段时线性扫描
var anyType = key.StartsWith("*|", StringComparison.Ordinal);
var anyBrand = key.EndsWith("|*", StringComparison.Ordinal);
if (!anyType && !anyBrand)
{
return null;
}
foreach (var info in _driverIndex.Values)
{
if (!anyType && !string.Equals(info.DriverType?.Trim(), driverType?.Trim(), StringComparison.OrdinalIgnoreCase))
{
continue;
}
if (!anyBrand && !string.Equals(info.Brand?.Trim(), brand?.Trim(), StringComparison.OrdinalIgnoreCase))
{
continue;
}
return info;
}
return null;
}
///
/// 用鸭子反射读取 [DriverDesc] 注解的 Type/Brand 属性值。
/// 宿主基础设施不引用 Driver.Core,只按"属性名"解耦读取,
/// 这样厂商 SDK 升级/换版本不会影响宿主。
///
private static Tuple ReadDriverDesc(Type type)
{
foreach (var attr in type.GetCustomAttributes(false))
{
var attrType = attr.GetType();
if (!attrType.Name.Equals("DriverDescAttribute", StringComparison.OrdinalIgnoreCase))
{
continue;
}
var typeProp = attrType.GetProperty("Type");
var brandProp = attrType.GetProperty("Brand");
if (typeProp == null || brandProp == null)
{
continue;
}
return Tuple.Create(typeProp.GetValue(attr, null) as string,
brandProp.GetValue(attr, null) as string);
}
return null;
}
private static string DriverKey(string driverType, string brand)
{
var t = string.IsNullOrWhiteSpace(driverType) ? "*" : driverType.Trim().ToUpperInvariant();
var b = string.IsNullOrWhiteSpace(brand) ? "*" : brand.Trim().ToUpperInvariant();
return $"{t}|{b}";
}
///
/// 列出某个类型的公共方法(属性访问器会被过滤掉)。
///
public DriverMethodInfo[] GetMethods(string typeFullName)
{
var type = ResolveType(typeFullName);
if (type == null)
{
return new DriverMethodInfo[0];
}
return GetMethodInfos(type)
.Select((m, i) =>
{
var parameters = m.GetParameters();
return new DriverMethodInfo
{
Index = i,
Name = m.Name,
IsStatic = m.IsStatic,
ParameterCount = parameters.Length,
Signature = BuildSignature(m),
Parameters = parameters
.Select(p => $"{FormatTypeName(p.ParameterType)} {p.Name}")
.ToArray()
};
})
.ToArray();
}
#endregion
#region 实例管理
private sealed class ManagedInstance
{
public Type Type;
public object Target;
}
///
/// 创建驱动类型的新实例(不走 Invoke 的默认缓存实例),按句柄登记供 DriverManager 管理。
///
public DriverInstance CreateInstance(string typeFullName, string driverType, string brand)
{
var type = ResolveType(typeFullName)
?? throw new InvalidOperationException($"未找到类型: {typeFullName}");
var ctor = type.GetConstructor(Type.EmptyTypes)
?? throw new MissingMethodException(typeFullName, ".ctor(缺少公共无参构造函数)");
var target = ctor.Invoke(null);
var handle = Guid.NewGuid().ToString("N");
_managedInstances[handle] = new ManagedInstance { Type = type, Target = target };
return new DriverInstance(this, handle, type.FullName, driverType, brand);
}
///
/// 在指定句柄的驱动实例上按"原始对象参数"直接调用方法,
/// 保留原始返回值与 out/ref 回填值(供 RealProxy 动态代理使用)。
///
public InvokeDirectResult InvokeOnInstanceDirect(string handle, int methodIndex, object[] args)
{
var result = new InvokeDirectResult();
if (!_managedInstances.TryGetValue(handle, out var managed))
{
result.Success = false;
result.Error = $"实例不存在或已释放: {handle}";
return result;
}
var methods = GetMethodInfos(managed.Type);
if (methodIndex < 0 || methodIndex >= methods.Length)
{
result.Success = false;
result.Error = $"方法索引无效: {methodIndex}(共 {methods.Length} 个方法)";
return result;
}
try
{
var method = methods[methodIndex];
var parameters = method.GetParameters();
args = args ?? new object[0];
if (parameters.Length != args.Length)
{
result.Success = false;
result.Error = $"参数数量不匹配: {method.Name} 需要 {parameters.Length} 个,实际传入 {args.Length} 个";
return result;
}
var converted = new object[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{
converted[i] = CoerceArg(args[i], parameters[i].ParameterType, parameters[i].Name);
}
result.Value = method.Invoke(managed.Target, converted);
result.ArgsOut = converted;
result.Success = true;
return result;
}
catch (TargetInvocationException ex)
{
var inner = ex.InnerException ?? ex;
result.Success = false;
result.Error = $"{inner.GetType().Name}: {inner.Message}";
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Error = $"{ex.GetType().Name}: {ex.Message}";
return result;
}
}
///
/// 在指定句柄的驱动实例上反射调用方法(实际执行发生在驱动自己的域内)。
///
public InvokeResult InvokeOnInstance(string handle, int methodIndex, string[] rawArgs)
{
if (!_managedInstances.TryGetValue(handle, out var managed))
{
return Fail($"实例不存在或已释放: {handle}");
}
var methods = GetMethodInfos(managed.Type);
if (methodIndex < 0 || methodIndex >= methods.Length)
{
return Fail($"方法索引无效: {methodIndex}(共 {methods.Length} 个方法)");
}
return ExecuteMethod(methods[methodIndex], managed.Target, rawArgs);
}
///
/// 释放指定句柄的实例;驱动实现 IDisposable 时会调用 Dispose。
///
public void ReleaseInstance(string handle)
{
if (!_managedInstances.TryGetValue(handle, out var managed))
{
return;
}
_managedInstances.Remove(handle);
(managed.Target as IDisposable)?.Dispose();
}
#endregion
#region 调用
///
/// 反射调用指定类型的方法。
/// 实例方法会自动用公共无参构造函数创建(并缓存)实例;
/// 静态方法无需实例。需要长期持有实例请使用 。
///
/// 字符串形式的实参,由 按目标参数类型转换
public InvokeResult Invoke(string typeFullName, int methodIndex, string[] rawArgs)
{
try
{
var type = ResolveType(typeFullName);
if (type == null)
{
return Fail($"未找到类型: {typeFullName}");
}
var methods = GetMethodInfos(type);
if (methodIndex < 0 || methodIndex >= methods.Length)
{
return Fail($"方法索引无效: {methodIndex}(共 {methods.Length} 个方法)");
}
var method = methods[methodIndex];
object target = null;
if (!method.IsStatic)
{
target = GetOrCreateInstance(type);
if (target == null)
{
return Fail($"无法实例化 {type.FullName}: 缺少公共无参构造函数。可改为只调用该类型的静态方法。");
}
}
return ExecuteMethod(method, target, rawArgs);
}
catch (TargetInvocationException ex)
{
// 驱动内部抛出的异常
var inner = ex.InnerException ?? ex;
return Fail($"{inner.GetType().Name}: {inner.Message}");
}
catch (Exception ex)
{
return Fail($"{ex.GetType().Name}: {ex.Message}");
}
}
///
/// 参数转换 → 反射调用 → 汇总返回值与 out/ref 回填值。
///
private static InvokeResult ExecuteMethod(MethodInfo method, object target, string[] rawArgs)
{
try
{
var parameters = method.GetParameters();
rawArgs = rawArgs ?? new string[0];
if (parameters.Length != rawArgs.Length)
{
return Fail($"参数数量不匹配: {method.Name} 需要 {parameters.Length} 个参数,实际传入 {rawArgs.Length} 个");
}
var args = new object[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{
args[i] = ConvertArg(rawArgs[i], parameters[i].ParameterType, parameters[i].Name);
}
var returnValue = method.Invoke(target, args);
// 汇总返回值与 out/ref 回填值(如 Open(out string msg) 的 msg)
var parts = new List();
if (method.ReturnType != typeof(void))
{
parts.Add($"返回: {Format(returnValue)}");
}
for (var i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType.IsByRef)
{
parts.Add($"{parameters[i].Name} = {Format(args[i])}");
}
}
return new InvokeResult { Success = true, Output = parts.Count == 0 ? "null" : string.Join("; ", parts) };
}
catch (TargetInvocationException ex)
{
// 驱动内部抛出的异常
var inner = ex.InnerException ?? ex;
return Fail($"{inner.GetType().Name}: {inner.Message}");
}
catch (Exception ex)
{
return Fail($"{ex.GetType().Name}: {ex.Message}");
}
}
private object GetOrCreateInstance(Type type)
{
if (_instances.TryGetValue(type, out var existing))
{
return existing;
}
if (type.IsAbstract || type.IsInterface)
{
return null;
}
var ctor = type.GetConstructor(Type.EmptyTypes);
if (ctor == null)
{
return null;
}
var instance = ctor.Invoke(null);
_instances[type] = instance;
return instance;
}
#endregion
#region 辅助
private Type ResolveType(string typeFullName)
{
if (_types.TryGetValue(typeFullName, out var type))
{
return type;
}
// 兜底:在已加载的驱动程序集里查找
type = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic)
.Select(a => a.GetType(typeFullName))
.FirstOrDefault(t => t != null);
if (type != null)
{
_types[typeFullName] = type;
}
return type;
}
private MethodInfo[] GetMethodInfos(Type type)
{
if (_methodCache.TryGetValue(type.FullName, out var cached))
{
return cached;
}
var methods = type
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)
.Where(m => !m.IsSpecialName) // 过滤 get_/set_/add_/remove_ 等
.ToArray();
_methodCache[type.FullName] = methods;
return methods;
}
private static string BuildSignature(MethodInfo method)
{
var parameters = method.GetParameters()
.Select(p => $"{FormatTypeName(p.ParameterType)} {p.Name}");
return $"{(method.IsStatic ? "static " : string.Empty)}{FormatTypeName(method.ReturnType)} "
+ $"{method.Name}({string.Join(", ", parameters)})";
}
private static string FormatTypeName(Type type)
{
if (!type.IsGenericType)
{
return type.Name;
}
var name = type.Name.Substring(0, type.Name.IndexOf('`'));
var args = string.Join(", ", type.GetGenericArguments().Select(FormatTypeName));
return $"{name}<{args}>";
}
///
/// 把跨域代理传来的对象参数适配为目标参数类型:
/// 类型兼容直接用,否则退化为字符串转换(鸭子式宽松匹配)。
///
private static object CoerceArg(object arg, Type targetType, string parameterName)
{
if (targetType.IsByRef)
{
targetType = targetType.GetElementType();
}
if (arg == null)
{
return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
}
if (targetType.IsInstanceOfType(arg))
{
return arg;
}
return ConvertArg(arg.ToString(), targetType, parameterName);
}
///
/// 把 UI 传来的字符串转换为目标参数类型。
/// 支持常用基元类型、枚举、Guid、DateTime、字符串数组(以分号分隔)。
///
private static object ConvertArg(string raw, Type targetType, string parameterName)
{
raw = raw ?? string.Empty;
// out/ref 参数实际按其元素类型转换(调用后由 CLR 回填)
if (targetType.IsByRef)
{
targetType = targetType.GetElementType();
}
if (targetType == typeof(string) || targetType == typeof(object))
{
return raw;
}
if (raw.Length == 0 && !targetType.IsValueType)
{
return null;
}
if (targetType == typeof(bool)) return bool.Parse(raw);
if (targetType == typeof(char)) return raw[0];
if (targetType == typeof(byte)) return byte.Parse(raw);
if (targetType == typeof(sbyte)) return sbyte.Parse(raw);
if (targetType == typeof(short)) return short.Parse(raw);
if (targetType == typeof(ushort)) return ushort.Parse(raw);
if (targetType == typeof(int)) return int.Parse(raw);
if (targetType == typeof(uint)) return uint.Parse(raw);
if (targetType == typeof(long)) return long.Parse(raw);
if (targetType == typeof(ulong)) return ulong.Parse(raw);
if (targetType == typeof(float)) return float.Parse(raw);
if (targetType == typeof(double)) return double.Parse(raw);
if (targetType == typeof(decimal)) return decimal.Parse(raw);
if (targetType == typeof(Guid)) return Guid.Parse(raw);
if (targetType == typeof(DateTime)) return DateTime.Parse(raw);
if (targetType.IsEnum) return Enum.Parse(targetType, raw, true);
if (targetType.IsArray)
{
var elementType = targetType.GetElementType();
var parts = raw.Length == 0 ? new string[0] : raw.Split(';');
var array = Array.CreateInstance(elementType, parts.Length);
for (var i = 0; i < parts.Length; i++)
{
array.SetValue(ConvertArg(parts[i], elementType, parameterName), i);
}
return array;
}
throw new InvalidOperationException(
$"参数 {parameterName} 的类型 {targetType.Name} 暂不支持从字符串转换(支持:字符串、数字、bool、枚举、Guid、DateTime、数组)");
}
private static string Format(object value)
{
if (value == null)
{
return "null";
}
if (value is string text)
{
return Truncate(text);
}
if (value is Array array)
{
var items = array.Cast