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))) __unep@?endl@std@@$$FYAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@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.

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

  1. 前端学HTTP之Web主机托管

    前面的话 对内容资源的存储.协调以及管理的职责统称为Web主机托管.主机托管是Web服务器的主要功能之一.保存并提供内容,记录对内容的访问以及管理内容都离不开服务器.如果不想自行管理服务器所需的软硬件 ...

  2. 解决托管在Windows上的Stash的Pull request无法合并的问题

    最近尝试合并一个托管在Windows的Stash系统中的pull request时,发现合并按钮被禁用,显示有冲突不能合并,但是在diff页面中没有现实冲突,而且代码实际上并没有任何冲突. 后来在这篇 ...

  3. 借助GitHub托管你的项目代码

    PS:话说自己注册了GitHub都很久了,却没有怎么去弄,现在系统学习一下,也把自己的学习经历总结下来share给大家,希望大家都能把GitHub用起来,把你的项目代码happy地托管起来! 一.基本 ...

  4. CSharpGL(36)通用的非托管数组排序方法

    CSharpGL(36)通用的非托管数组排序方法 如果OpenGL要渲染半透明物体,一个方法是根据顶点到窗口的距离排序,按照从远到近的顺序依次渲染.所以本篇介绍对 UnmanagedArray< ...

  5. ASP.NET Core 中文文档 第三章 原理(12)托管

    原文:Hosting 作者:Steve Smith 翻译:娄宇(Lyrics) 校对:何镇汐.许登洋(Seay) 为了运行 ASP.NET Core 应用程序,你需要使用 WebHostBuilder ...

  6. CLR via C# 摘要一:托管程序的执行模型

    托管程序的执行模型大致如下: 编译源代码为程序集(dll或exe文件),程序集包括了记录相关信息的元数据和IL代码 执行程序集文件时,启动CLR,JIT负责把IL编译为本地代码并执行 IL是微软推出的 ...

  7. 【CLR via C#】CSC将源代码编译成托管模块

    下图展示了编译源代码文件的过程.如图所示,可用支持 CLR 的任何一种语言创建源代码文件.然后,用一个对应的编译器检查语法和分析源代码.无论选用哪一个编译器,结果都是一个托管模块(managedmod ...

  8. 国内git项目托管平台

    以前一直使用github托管项目,最近换了阿里云的vps,连接github出奇的慢,找了一下国内的代码托管平台. 有几个都不错,我刚好有csdn的账号,就试了一下csdn的托管平台,创建一个项目,发现 ...

  9. 【配置】检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(非简单设置为【经典】模式)。

      ×   检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(非简单设置为[经典]模式). 我们将ASP.NET程序从IIS6移植到IIS7,可能运行提示以下错误: HTTP 错误 5 ...

  10. 两个坑-Linux下Network-Manager有线未托管-DNS resolv.conf文件开机被清空

    Linux里面有两套管理网络连接的方案: 1./etc/network/interfaces(/etc/init.d/networking) 2.Network-Manager 两套方案是冲突的,不能 ...

随机推荐

  1. [转载]ExtJs4 笔记(2) ExtJs对js基本语法扩展支持

    作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/) 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引 ...

  2. K-means算法的优缺点

    K-means算法的优缺点 优点:原理简单,实现容易 缺点: 收敛较慢 算法时间复杂度比较高 \(O(nkt)\) 不能发现非凸形状的簇 需要事先确定超参数K 对噪声和离群点敏感 结果不一定是全局最优 ...

  3. Tomcat 禁用PUT方法, 404/500错误重定向, 网站图标

    (1) Tomcat禁用Put等不安全方法. <security-constraint> <web-resource-collection> <web-resource- ...

  4. TOJ1017: Tour Guide

      描述 You are working as a guide on a tour bus for retired people, and today you have taken your regu ...

  5. javascript基础2 判断 数据类型

    js中的数据类型: ------------------------------------------------------------------------------- 返回undefine ...

  6. js原型链继承的傻瓜式详解

    本文争取用最简单的语言来讲解原型链继承的OOP原理 0.如果对原型继承还没有大致了解,完全一头雾水,请先阅读 <JavaScript高级程序设计>第六章最后部分的寄生组合式继承 或者_廖雪 ...

  7. Docker网络基础:快速指南

    Docker网络基础:快速指南 原文连接:http://blogxinxiucan.sh1.newtouch.com/2017/07/30/Docker网络基础:快速指南/ 了解有关扩展网络功能的默认 ...

  8. 【Luogu】P3155叶子的染色(树形DP)

    题目链接 树形DP水题qwq. 设f[i][j]是以i为根的子树,染成j色,且满足内部需求的最少染色节点数. 设to是x的子节点,那么状态转移方程如此设计: 1.f[i][0] 这个状态表示i不染色, ...

  9. 归并排序,时间复杂度nlogn

    思路: /*   考点:   1. 快慢指针:2. 归并排序.   此题经典,需要消化吸收.   复杂度分析:              T(n)            拆分 n/2, 归并 n/2 ...

  10. Miracast HDCP 等知识

    Miracast 通讯架构中关于视频数据处理流程的部分.整个视频数据处理及传输的流程,大致上分为几个阶段,一开始将撷取到系统的画面及声音进行压缩,而压缩后的影音数据再转为基本封包串流(Packetiz ...