zoukankan      html  css  js  c++  java
  • .net下com调用支持x86/x64

    起因

    项目涉及u3d/wpf端的渲染图形合成,采用了开源项目spout,为了便捷,采用了spout的com版本作为c#端的调用
    项目调整后,细节已经捋清楚了。
    但是考虑桌面应用采用anypc,根据运行环境自动切换x86/x64,就不想硬编码绑定运行环境了。
    故选项后采用 程序选择anypc,运行时动态判断x86/x64,加载对应的com组件
    封装代理层,代理层调用对应的x86/x64 com pinvoke

    封装分析

    项目 LightjamsSpout
    我们需要封装的部分是

    GLContext和LightjamsSpoutReceiver
    都是com接口,硬编码直接实例化即可,动态调用时,不能实例化接口,需要通过反射拿到类型上面的特性 CoClassAttribute
    通过获取 CoClassAttribute.CoClass 拿到实际类型去实例化
    将x86/x64的库分别放在不同的路径,通过判断 IntPtr.Size == 4/!Environment.Is64BitProcess 判断是否是x86,反之则为x64
    通过项目的引用,把com组件转换成 Interop.xx.dll ,路径为项目文件/obj/Debug,项目动态加载实际上是这个 Interop.xx.dll

    代码实现

    代理端动态加载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对应的引用类型
    毕竟定义是

    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内部的自定义枚举类型
    根据内容,做一个枚举类型

        public enum NePixelFormat
        {
            BGR,
            RGB
        }
    

    表达式树的参数2改为int,内部转换 Expression.Convertint 转换成对应的 LightjamsSpoutLib.EPixelFormat
    调用函数的参数2改为NePixelFormat,内部调用委托时,转换成int即可

            public void ReceiveImage(System.Array bytes, NePixelFormat format)
            {
                _receiveImage.Invoke(bytes, (int)format);
            }
    
  • 相关阅读:
    合格linux运维人员必会的30道shell编程实践题及讲解-07
    合格linux运维人员必会的30道shell编程实践题及讲解-06
    合格linux运维人员必会的30道shell编程实践题及讲解-05
    合格linux运维人员必会的30道shell编程实践题及讲解-04
    合格linux运维人员必会的30道shell编程实践题及讲解-03
    合格linux运维人员必会的30道shell编程实践题及讲解-02
    合格linux运维人员必会的30道shell编程实践题及讲解-01
    阿里云服务器环境部署
    centos7搭建docker私有库
    Hexo+Github--搭建个人博客(一)准备工作&&环境搭建
  • 原文地址:https://www.cnblogs.com/NCoreCoder/p/14172775.html
Copyright © 2011-2022 走看看