项目涉及u3d/wpf端的渲染图形合成,采用了开源项目spout,为了便捷,采用了spout的com版本做为c#端的调用
项目调整后,细节已经捋清楚了。
可是考虑桌面应用采用anypc,根据运行环境自动切换x86/x64,就不想硬编码绑定运行环境了。
故选项后采用 程序选择anypc,运行时动态判断x86/x64,加载对应的com组件
封装代理层,代理层调用对应的x86/x64 com pinvokegit
项目 LightjamsSpout
咱们须要封装的部分是github
GLContext和LightjamsSpoutReceiver
都是com接口,硬编码直接实例化便可,动态调用时,不能实例化接口,须要经过反射拿到类型上面的特性 CoClassAttribute
经过获取 CoClassAttribute.CoClass 拿到实际类型去实例化
将x86/x64的库分别放在不一样的路径,经过判断 IntPtr.Size == 4/!Environment.Is64BitProcess 判断是不是x86,反之则为x64
经过项目的引用,把com组件转换成 Interop.xx.dll ,路径为项目文件/obj/Debug,项目动态加载其实是这个 Interop.xx.dllc#
代理端动态加载Assmebly函数
loadDirectory = Path.Combine(Directory.GetCurrentDirectory(), IntPtr.Size == 4 ? "x86_Spout" : "x64_Spout");//LightjamsSpoutPS.dll var loadFile = Path.Combine(loadDirectory, "Interop.LightjamsSpoutLib.dll"); assembly = Assembly.LoadFile(loadFile); var type = assembly.GetType("LightjamsSpoutLib.LightjamsSpoutReceiver"); var coClassAttribute = type.GetCustomAttribute<CoClassAttribute>(); try { instance = Activator.CreateInstance(coClassAttribute.CoClass); } catch (Exception e) { RegisterCom(loadDirectory); instance = Activator.CreateInstance(coClassAttribute.CoClass); }
经过表达式树构建实例的方法
好比LightjamsSpoutReceiver.Connect编码
delegate string ConnectInvoke(string senderName, out int width, out int height); private ConnectInvoke CreateConnect() { var senderNameParam = Expression.Parameter(typeof(string), "senderName"); var widthParam = Expression.Parameter(typeof(int).MakeByRefType(), "width"); var heightParm = Expression.Parameter(typeof(int).MakeByRefType(), "height"); var instanceExp = Expression.Constant(instance); var method = instance.GetType().GetMethod("Connect"); var callExp = Expression.Call(instanceExp, method, new Expression[]{ senderNameParam, widthParam, heightParm }); return Expression.Lambda<ConnectInvoke>(callExp, new ParameterExpression[]{ senderNameParam, widthParam, heightParm }).Compile(); }
值得一提的是type.MakeByRefType是生成type对应的引用类型
毕竟定义是3d
public virtual string Connect(string senderName, out int width, out int height)
有一个函数ReceiveImage,参数调用了com内部类型代理
public virtual void ReceiveImage(System.Array bytes, LightjamsSpoutLib.EPixelFormat format)
LightjamsSpoutLib.EPixelFormat是com内部的自定义枚举类型
根据内容,作一个枚举类型code
public enum NePixelFormat { BGR, RGB }
表达式树的参数2改成int,内部转换 Expression.Convert 把 int 转换成对应的 LightjamsSpoutLib.EPixelFormat
调用函数的参数2改成NePixelFormat,内部调用委托时,转换成int便可orm
public void ReceiveImage(System.Array bytes, NePixelFormat format) { _receiveImage.Invoke(bytes, (int)format); }