您也使用托管C++吗? 【转】

http://blog.csdn.net/Muf/article/details/656920

转向.NET后,手头上往往仍有旧的模块要重用。也许这些模块是Delphi写的,也许是C/C++写的,或者是其它编程语言……为了能把它们移植到.NET下,或者是在.NET中调用,To be or not to be, that is a question。
  在这里,我笔记了几个在工作中遇到的几个场景。不过,这里不包括完全使用C#来重写原来用C++编写的程序这种变态的需求。当你被要求做这种事的时候,请三思而后行……这简直是种非人的折磨。

您也使用托管C++吗?  如沐枫林

  场景一:在.NET中调用WindowsAPI或DLL。

  这是比较普遍的需求。一般来说,简单的函数调用,大可直接用C#/VB.NET,经过DllImport属性包装出函数来调用。如:

="MoveFileW",  SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern bool MoveFile(String src, String dst);

  由于WindowsAPI用到的人实在是多,因此有一个专门的wiki站点,收集这方面的资料:http://www.pinvoke.net/,对于常用的函数甚至有完整的应用例子和帮助。当然,如果你有相应的资料和例子,你也可以贡献你的力量,给其它人帮助。

  场景二:用托管C++包装现有的DLL,供C#调用

  当函数的参数或返回值比较复杂,或函数比较多的时候,这种方法对与人来说,实在是一个折磨。常常这些接口和定义就要用掉几千行的代码,而且还不能保证是正确的。这些错误往往在运行时才能显现出来,甚至有些错误会引起内存泄漏,或其它更为隐蔽的错误。
  在这种情况下,使用C++/Managed代码来包装,就成了最合理的选择。因为托管C++代码可以直接引用原有的头文件,直接调用非托管函数,而不需要声明。这样,既减少了工作量,又避免引入错误。缺点是,这种方法会增加一个DLL。要注意的是托管字符串和非托管字符串是有区别的,并需要转换(特别要注意的Unicode字符串和多字节字符串的转换)。

  仍以MoveFile为例吧,这样比较简单:

<windows.h>
#include <vcclr.h>

using namespace System;

namespace wrapper
{
    public ref class ApiWrapper {
    public:
        bool static MoveFile(String ^ lpExistingFileName, String ^ lpNewFileName )
        {
            pin_ptr<const wchar_t> src = PtrToStringChars(lpExistingFileName);
            pin_ptr<const wchar_t> dst = PtrToStringChars(lpNewFileName);
            return ::MoveFile(src, dst);
        }
    };
}

  然后在C#中,引用上面代码生成的DLL文件,就可以直接调用了:

@"c:/debug.txt");

  假如原有的代码是基于COM的,那么太好了,VisualStudio等IDE会自动生成一个用于包装的dll,供你调用。当然因特殊需要而手工编码的是另一回事。

  场景三:现有C++原代码,包装后供C#调用。

 
 C++的原代码,实际上可以直接编译成托管代码。MFC也好ATL也好……这样看起来在.NET中最强大的编程语言就是C++了:它不仅可以编写托管程
序,甚至可以将标准C++的代码也编译成托管程序!其实VC++最强大的地方不止如此,它还在于能够编写混合了托管和非托管的代码的程序!!!这样最大的
好处不仅可以将关键代码直接编译成非托管的代码,还可以避免被反编译。
  
  假设现有C++代码如下:

{
public:
    LPCWSTR GetPropertyA() { return L"Hello!"; }
    void MethodB( LPCWSTR ) {}
};

  我们只要再增加一个包装类到工程文件中:

{
    public ref class ManagedClass {
    public:
        // Allocate the native object on the C++ Heap via a constructor
        ManagedClass() : m_Impl( new UnmanagedClass ) {}

        // Deallocate the native object on a destructor
        ~ManagedClass() {
            delete m_Impl;
        }

    protected:
        // Deallocate the native object on the finalizer just in case no destructor is called
        !ManagedClass() {
            delete m_Impl;
        }

    public:
        property String ^  get_PropertyA {
            String ^ get() {
                return gcnew String( m_Impl->GetPropertyA());
            }
        }

        void MethodB( String ^ theString ) {
            pin_ptr<const WCHAR> str = PtrToStringChars(theString);
            m_Impl->MethodB(str);
        }

    private:
        UnmanagedClass * m_Impl;
    };
}

  然后,改变编译选项为“使用公共语言扩展 /clr”就可以了。这样,我们把代码编译成DLL文件就可以供.NET其它语言调用了。
  最后,C#中可以象如下的代码一样调用C++类了:

= new ManagedClass();
mc.MethoB("Hello");
string s = mc.get_PropertyA;

  场景四:如何在托管C++代码中混合托管和非托管代码

  很简单,只要从#pragma unmanaged编译指示开始的程序,一率编译成非托管代码;要想恢复成托管代码,只要使用#pragma managed就可以了。如:
  


#include <iostream>
using namespace std;

template<typename T>
void f(T t){
    cout << t << endl;
}

#pragma managed

using namespace System;

void m(String ^ s){
    Console::WriteLine(s);
}

void main(){
    f("Hello");
    m("World");
}

  
  生成exe文件后,用反编译程序查看 f 函数:

=MethodCodeType.Native), SuppressUnmanagedCodeSecurity]
public static unsafe void modopt(CallConvCdecl) f<char const *>(sbyte modopt(IsSignUnspecifiedByte) modopt(IsConst)*);

  
  看不到源码,而方法属性标记为Unmanaged。
  如果没有加上#pragma unmanaged,反编译得到的 f 函数为:

static unsafe void modopt(CallConvCdecl) f<char const *>(sbyte modopt(IsSignUnspecifiedByte) modopt(IsConst)* t)
{
      std.basic_ostream<char,std::char_traits<char> >.<<(std.operator<<<struct std::char_traits<char> >(*((basic_ostream<char,std::char_traits<char> >* modopt(IsImplicitlyDereferenced)*) &__imp_std.cout), t), (basic_ostream<char,std::char_traits<char> >* modopt(IsImplicitlyDereferenced) modopt(CallConvCdecl) *(basic_ostream<char,std::char_traits<char> >* modopt(IsImplicitlyDereferenced))) [email protected]?[email protected]@@$$FYAAAV?[email protected]?[email protected]@[email protected]@@1@[email protected]@Z);
}

  其中的函数内容一目了然。如果你的函数没有调用operator等不好理解的类库,那么反编译出来的代码简直和源码没差别。

  场景五:不想要DLL,能不能直接把C++源代码与C#源代码一起编译成一个单独的Assembly呢?

  当然是可以的。具体参见:让C++源码和C#源码一起生成单一的Assembly

  开心一刻:我只会C++不懂.NET不懂C#,怎么编写.NET程序?

  很简单,你照样用你的C++写你的程序,然后测试没有错误后,将编译选项改为/clr,好了,Rebuild,你的程序现在是.NET了。

  恶搞:“我想问一下,在能将现有的C++代码直接进行封装,被C#进行调用,而不是去调用DLL,也就是不生成DLL,就在C#下能直接调用VC的工程源文件不?”

  我想,提问的人是不是指,现有c++源码,但不想费劲去转换成C#源码,但又想能与C#一起编译。
  于是我就给了一个极其变态的方法,不过,个人是不建议使用这种变态的方法啊。方法如下:
  1 先将C++源码,改用CLR编译选项,编译成.NET的Assembly(DLL文件)。
  2 然后用reflector等反编译软件,反编译成C#代码,并导出(reflector有专门的导出插件)。
  3 将导出的C#代码,添加上新写的C#代码一起编译。
  
  这种方法生成的代码很是恐怖,强烈建议不要把C++源码就这么丢了,否则后果自负。
-------
部份例子来自MSDN.

时间: 2024-10-20 17:28:40

您也使用托管C++吗? 【转】的相关文章

TortoiseGit配合msysGit在[email&#160;protected]代码托管的傻瓜教程

命令行太麻烦,肿么破?便便利用睡觉的时间解决了一点效率问题,tortoiseGit处理GitHub,一样可以处理 Git @osc ,虽然说可以用gitk来调出图形界面,but,我就是不想看见黑黑的命令提示符的框框,于是乎,近乎龟毛到变态的便便又开始了新的折腾.... OK,windows系统,linux和mac勿喷..... 下载msysgit http://msysgit.github.io/ 下载TortoiseGit http://code.google.com/p/tortoisegi

公司网站服务器为什么要托管?

1.服务器不是普通电脑,它需要24小时全天开着机,365天从不间断的工作,如果是普通电脑,是承担不了这样的工作的.所以它的配置要求就比较高,而电脑的散热也更为重要,因而服务器需要放置在一个相对稳定适宜的环境中,恒温.恒湿.防尘.供电等必不可少.普通公司很难有条件专门为服务器建立一间机房,那有人就会说:用空调保证恒温恒湿防尘供电呢?适宜人生存的温度不适用于服务器,相反适宜服务器的温度又不是适应人的生存.而且这方面的维护成本会很高.西安天互通信有限公司,主要从事于IDC服务业务.对于服务器托管,自己

【仿乐享微信源码】利用第三方微信营销托管平台快速增加粉丝,形成良好互动,打造精美微信APP

99%的人不知道的微信秘密!微信里的商机.仿乐享微信源码分享,把你的生意做到微信里. WeiKuCMS  (微酷CMS)功能特点:人工客服新功能正式上线!粉丝行为分析.渠道二维码生成.二维码折扣,微菜单,微统计,会员卡签到,微会员,刮刮卡,大转盘,优惠券,积分兑换,微官网,砸金蛋,微调研,微投票,微相册,微商城,微团购,微留言,微喜帖,商家入驻,微门店,微餐饮,微酒店,微教育,微物业,微医疗,微信墙,微花店,微美容,微生活. 微信公共账号轻松接入,无限自定义图文回复.欢迎您的加入! 微酷WeiK

还在使用pdf、word简历?简单五步实现github托管个人逼格简历

写在前面: 什么是git.github? git 版本控制工具 github 通过git工具做的版本控制的项目托管平台 项目开发肯定不止一个程序猿,多个程序猿针对同一个文件进行代码读写操作时,是先保存程序猿a还是程序猿b呢?这就很容易冲突,所以就有了git这种版本控制工具解决项目更新.慢慢的随着开源精神的发展以及在线的需求就有了github项目托管平台,对于git本地服务来说,github就是一个远程的仓库. 逼格在哪里? Github已经取代Sourceforge,成为最活跃的代码交流社区,一

C#非托管跨线程委托调试

使用C#调用mingw的so文件,拿视频数据回wpf的界面进行显示,注册了回调函数.C++在调用回调函数时遇到了委托被回收的问题,提示:"类型的已垃圾回收委托进行了回调.这可能会导致应用程序崩溃.损坏和数据丢失.向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们."此问题在程序正常运行一段时间后出现.从gdb调试器中看到的效果是所有变量都正常,运行到回调函数时segmentation fault 通过c++直接调用opencv的imshow显示图像

c++通过CLRCreateInstance调用托管dll

C++手动加载CLR运行托管程序(CLR Hosting) 非原创,记录方便翻阅(另外一种调用方式为将托管dll封装成com) 机制介绍 有些时候主程序是通过C/C++实现的,但是我们希望通过托管代码来扩展非托管程序,从而也获得托管代码带来的一系列优点.比如开发效率高,自动垃圾回收等. 运行托管与非托管代码根本区别在于托管代码是进程首先加载CLR然后通过CLR运行托管程序,而非托管代码则是操作系统直接根据其PE Header加载程序分配内存从而运行.因此如果需要通过托管代码来扩展非托管程序,首先

GitHub托管

借助GitHub托管你的项目代码 PS:话说自己注册了GitHub都很久了,却没有怎么去弄,现在系统学习一下,也把自己的学习经历总结下来share给大家,希望大家都能把GitHub用起来,把你的项目代码happy地托管起来! 一.基本概念 1.1 必须了解的概念 (1)仓库 - Repository 仓库即你的项目,你想在GitHub上开源一个项目,那就必须要新建一个Repository.如果你开源的项目有多个,那么你就有多个Repositories. (2)收藏 - Star 收藏项目,方便下

检测到在集成的托管管道模式下不适用的 ASP.NET 设置。

我们将ASP.NET程序从IIS6移植到IIS7,可能运行提示以下错误: HTTP 错误 500.23 - Internal Server Error 检测到在集成的托管管道模式下不适用的 ASP.NET 设置. 为什么会出现以上错误? 在IIS7的应用程序池有两种模式,一种是“集成模式”,一种是“经典模式”. 经典模式 则是我们以前习惯的IIS 6 的方式. 如果使用集成模式,那么对自定义的httpModules 和 httpHandlers 就要修改配置文件,需要将他们转移到<modules

C# DllImport“调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配 ”

调用外部dll时,出现如下问题 C# DllImport“调用导致堆栈不对称.原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配.请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配 ” 后来经过仔细检查发现,误把vb中的longx型当成64位,实际上它相当于C#中的32位int型.

iOS开发:(git项目托管)的使用

git托管网站是一个非常强大的网站,通过这个网站我们可以讲自己写出来的优秀的代码发布在这个网站上,通过这个网站我们可以对自己的代码进行推送,版本更新.好了,不多说了,我要总结一下git的使用流程. 1.登陆开源中国社区网站http://www.oschina.net 2.如果有账号和密码就可以登录,没有的话就先注册一个账号和密码 3.注册新用户成功后,下一步 4.现在需要做的就是登陆你的邮箱,激活账号,激活之后就可以登录了 5.登陆成功之后你可以完善你的资料,做下一步的工作了. 6.新建一个项目