知识大全 C#与NativeC++互相访问
Posted 知
篇首语:一切节省,归根到底都归结为时间的节省。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 C#与NativeC++互相访问相关的知识,希望对你有一定的参考价值。
C#与NativeC++互相访问 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
用C#做开发已经好几年了 一直用得挺顺手的 最近有一个项目需要用到DirectShow的相关组件 也就是想在C#的项目里面实现一个基于内存流的Filter 这个却让我着实头痛了好久
原因就是在C#里面没有现成的DirectShow的组件的定义 虽说在C#中可以使用一些特定的方式来操作组件(C#中操作(一)——实例化) 可是对于DirectShow这样需要声明一大批的接口 类型 枚举却是一件漫长又枯燥的事件 而且搞不好一个不小心中间出个错误 导致最后调试总不通过而抓狂 即便是现在有了DirectShow NET提供的对绝大部分的DirectShow的C#翻译 可是面对网上那么多的C++开源代码还有少得可怜的C#操作DirectShow的代码 你会怎么办?难道又是一行一行的翻译成C#吗 反正我是不会这样干的 于是这种方式首先被毙掉了
俗话说最优秀的程序员也是最懒的程序员 类和方法能公用的就尽量公用 已存在的实现就不需要自己再去写一次了 既然有现成的C++的实现好的代码为什么不可以再次拿来用一用呢 可是在C#里面想要使用C++的实现(注意这里我用的是实现 并没有指定是类或方法) 比较常见的是通过 DllImportAttribute特性导入相应的程序集 可是这种方式只可以调用方法 而且是限定死了的只能是C语言形式的导出方法 对于其它的方法是不可以的 以前用的最多的就是对Windows API的调用了 这样的使用形式极其不方便 C++和C#本都是都面向对象的语言 却要通过面向过程式的方法调用来相互通信 感觉很别扭也很不爽 对于追求完美的程序员来说 这也不是一个上上的选择 于是这种方式也不是最好的 暂时作为候选吧 再找找看还有没有其它的方式
后来我想到了以前看过一篇文章说的是在C++里面通过托管C++作为媒价调用C#里的代码 把这个反过来就是用C#通过托管C++调用NativeC++ 这样是否也是可行的呢?不过这都是好几年前看到的了 只怪那时候对于这种跨平台调用的方式研究不深 也不怎么感兴趣所以当时就没有太在意 对于文中所说的托管C++的印象也一直停留在中看不中用的程序上 如今也只得找来看看 虽说信心不大 也报著死马当活马医一回的心情试试先
其实前面已经提到过了 如果仅仅是对C++的导出方法的调用的话基本不是难事 可是C++是面向对象的语言 很多情况下都是以类的形式存在的 导出的也是 C++的类 就拿我找到的C++写的内存流的Filter来说吧 网上的代码都是基于类的 并且我想在C#里面控制FilterGraph的构建 解决怎么在C#里面直接或间接使用到这个类才是问题的本质和关键所在 网上找了几份资料 也查了MSDN 里面都说可以使用托管C++作Wrapper包装 NativeC++然后编译成CLI可识别的托管程序集就可以供C#调用了
class MemFilter : public IBaseFilterpublic:
private:
public ref class MemFilterWrapper : IBaseFilterprivate:MemFilter* m_pFilter;public:// 此处只只需要把MemFilter类的公有方法用托管方工声明一下 在方法的实现中直接调用m_pFilter中相应的成员方法就可以了
把这两个类都编译到同一个CLI/C++项目中去 这样在C#里面就可以直接使用MemFilterWrapper这个类间接操作C++类了 与其它普通的CLS类没什么区别 不过需要注意的是对于C++里面的一些基元类型 比如int char* bool等 包括数组需要用CLS里面相应的类型去替换 然后再对外公布成方法 也就是说把所有的与C++特性相关的都封装起来 对外只显示符合公共语言规范的格式 不然的话在使用的时候比较麻烦(有可能需要使用C#的不安全代码)
就像之前提到的那样 我们也可以通过使用托管C++让C#的类披上一层C++的皮 再声明成导出类 这样就可以供普通C++调用了(前是你必须先安装Framework)
public class CSharpClass // C# 类public void SayHello() Console WriteLine( Hello );
class NativeCPP // C++原生类代理 注意这里的参数返回值什么的都不能带有托管类型的痕迹public:void* m_pCSharpClass;NativeCPP(void);SayHello(void);
NativeCPP::NativeCPP(void)CSharpClass^ obj = new CSharpClass();GCHandle^ handle = GCHandle Alloc(obj)m_pCSharpClass = GCHandle::ToIntPtr(handle) ToPointer();
NativeCPP::SayHello(void)GCHandle handle = GCHandle::FromIntPtr(m_pCSharpClass);CSharpClass^ obj = dynamic_cast<CSharpClass^>(handle Target);obj SayHello();
不过这个时候有个问题 普通的C++类用new方式构造的实例可以用C++指针持有 在C++代码中没有调用delete的时候会一直存在于当前进程的地址空间中 这样在后面的使用中不会出现内存访问方面的问题 可是从C#到C++的过程就不是这的了 在C#中对象是由CLI自己管理的 当CLI发现一个对象不有直接或间接的引用存在的时候(也就是所谓的无根对象)就会被回收 这里的引用是指的CLI中的引用 另外C#的对象如果以引用的形式存在的话 那么在原始的C++里面中两个类之间传送这个对象将会变得不可能 因为除了托管C++外 其它的代码根本不能识别C#引用 只认识指针 因此我们必须把C# 中的引用转成指针 可是如果通过简单的方式一旦转成指针后C#中的对象很可能会在没有引用的时候被GC回收了 造成C++代码再去访问的时候出内存导常 MS提供了一个名叫GCHandle的结构来解决这样的问题 通过这个结构可以构造一块内存区域代表这个引用对象 GC发现有这么一块内存区域存在的时候不管什么情况下都不会对该对象进行回收 用用类似的方法也可以从给定的内存指针上返回所指代的托管对象的引用 而这块内存本身不受托管代码控制 反回的也只是一个指针 因此在整个C++的代码生命周期里都不用再担心会引用到无效的C#对象了
cha138/Article/program/net/201311/12726相关参考
VisualC#访问接口 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 对接口成员的访问 &n
上午看到一个兄弟的文章很辛苦的想实现不改代码只改配置来访问不同类型的数据库自己去实现工厂模式精神可嘉但是殊不知c#已经自己为不同类型数据库的访问做了一个工厂在这里我就把使用工厂的例子贴出来供不知道
在C#中跨线程访问Winform控件 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在程序需要读
我们在做winform应用的时候大部分情况下都会碰到使用多线程控制界面上控件信息的问题然而我们并不能用传统方法来做这个问题下面我将详细的介绍 首先来看传统方法 publicpartialcla
知识大全 在ASP.NET访问Excel文件 (VB and C#)
在ASP.NET访问Excel文件(VBandC#) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
知识大全 c#中private私有和public公有的区别是什么
c#中private私有和public公有的区别是什么private、protect、public、访问范围依次增大。private只限在本类中使用。protect允许它的子类访问。public修饰符
C#网站(二):访问需登录后才能访问 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &n
数据库准备:建立一个表total里面数据项为totals类型为varchar 语言环境:C# globalasax里的代码 <%@ImportNamespace=SystemData%
基于C#的接口基础教程之四 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 第四节访问接口 对接
用C#对ADO数据库完成简单操作 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 数据库访问是中应