起因

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

.net下com调用支持x86/x64的更多相关文章

  1. x86 x64下调用约定浅析

    x86平台下调用约定 我们都知道x86平台下常用的有三种调用约定,__cdecl.__stdcall.__fastcall.我们分别对这三种调用约定进行分析. __cdecl __cdecl是C/C+ ...

  2. 使用CefSharp在C#访问网站,支持x86和x64

    早已久仰CefSharp大名,今日才得以实践,我其实想用CefSharp来访问网站页面,然后抓取html源代码进行分析,如果使用自带的WebBrowser控件,可能会出现一些不兼容js的错误. Cef ...

  3. 关于.NET编译的目标平台(AnyCPU,x86,x64) (转)

    关于.NET编译的目标平台(AnyCPU,x86,x64)(转) 今天有项目的代码收到客户的反馈,要求所有的EXE工程的目标平台全部指定成x86,而所有DLL工程的目标平台全部指定成AnyCPU . ...

  4. windows7内核分析之x86&x64第二章系统调用

    windows7内核分析之x86&x64第二章系统调用 2.1内核与系统调用 上节讲到进入内核五种方式 其中一种就是 系统调用 syscall/sysenter或者int 2e(在 64 位环 ...

  5. X86/X64处理器体系结构及寻址模式

    由8086/8088.x86.Pentium发展到core系列短短40多年间,处理器的时钟频率差点儿已接近极限.尽管如此,自从86年Intel推出386至今除了添加一些有关流媒体的指令如mmx/sse ...

  6. 关于VS项目平台的x86,x64,Any CPU以及Debug和Release的区别

    相信对于很多刚接触打包程序的同志来说,关于x86,x64,Any CPU这三个项目平台,以及解决方案配置Debug和Release有什么区别?这个问题一定有许多的困惑,甚至不乏一些已经工作了很久的老程 ...

  7. 『开源重编译』System.Data.SQLite.dll 自适应 x86 x64 AnyCPU 重编译

    背景: > System.Data.SQLite.dll 程序集 不能良好的支持 AngCPU 格式 System.Data.SQLite.dll 在 适应 x86 和 x64 有三个方案: & ...

  8. 数据库管理工具GUI - PremiumSoft Navicat Premium Enterprise 11.2.15 x86/x64 KEY

    转载自: 数据库管理工具GUI - PremiumSoft Navicat Premium Enterprise 11.2.15 x86/x64 KEY Navicat Premium(数据库管理工具 ...

  9. QtCreator动态编译jsoncpp完美支持x86和arm平台

    如果是做嵌入式开发. 在Qt下支持JSon最好的办法,可能不是采用qjson这个库.QJson这个库的实例只提供了x86环境下的编译方法. Installing QJson-------------- ...

随机推荐

  1. 理解与使用Treiber Stack

    目录 背景 名称由来 CompletableFuture源码实现 FutureTask实现 Treiber Stack抽象实现 入栈 出栈 示例 参考 背景 最近在很多JDK源码中都看到了Treibe ...

  2. 数学分析理论(rudin版)笔记:实数系和复数系.2:抄书版

    有理数(rational number)记为 Q,实数记为 R 虽然任意两个不同的有理数间还有一个有理数,但是有理数集中还是会有 "间隙",而实数集填补了这些间隙. 集合(set) ...

  3. python菜鸟教程学习9:函数

    函数的定义 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.python提供了很多内建函数,但我们依然可以自己创建函数,叫做用户自定义函数. 自定义函数 你可以定义一个由自己想要功能 ...

  4. Codeforces Round #668 C. Balanced Bitstring (Div. 2)题解(思维)

    题目链接 题目大意 给你一个长为n的01串,要你使得每一个01串中0和1的个数都要相等,01串中有?字符,你可以使得这个字符变为0或1,要你求是否可以满足条件.输出YES或NO 题目思路 这个题目的难 ...

  5. 【mq学习整理】mq速览

  6. Linux无法新增用户

    1.查看当前用户是否有权限创建用户 2.磁盘空间不足,vi打开/etc/passwd 报: E297: Write error in swap file"adduser.sh" 1 ...

  7. LeetCode 030 Substring with Concatenation of All Words

    题目要求:Substring with Concatenation of All Words You are given a string, S, and a list of words, L, th ...

  8. Python中动态编译函数compile(source, filename, mode, ......)参数filename的作用是什么?

    动态编译函数compile调用语法如下: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) 其中的fi ...

  9. PyQt(Python+Qt)学习随笔:QDockWidget停靠部件的setTitleBarWidget方法

    setTitleBarWidget方法用于给停靠窗口设置个性化的标题栏,调用语法如下: setTitleBarWidget(QWidget widget) 说明: widget参数可以是任意一个QWi ...

  10. PyQt(Python+Qt)学习随笔:QTabWidget选项卡部件的tabBar、count、indexOf方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTabWidget的每个选项卡都有一个对应的页面部件对象,可用通过count方法获取选项卡个数,可 ...