項目涉及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); }