http://ly4cn.teeta.com/blog/data/77172.html
您也使用托管C++吗?(转载)2008年08月21日 星期四 下午 04:02 转向.NET后,手头上往往仍有旧的模块要重用。也许这些模块是Delphi写的,也许是C/C++写的,或者是其它编程语言……为了能把它们移植到.NET下,或者是在.NET中调用,To be or not to be, that is a question。
在这里,我笔记了几个在工作中遇到的几个场景。不过,这里不包括完全使用C#来重写原来用C++编写的程序这种变态的需求。当你被要求做这种事的时候,请三思而后行……这简直是种非人的折磨。
场景一:在.NET中调用WindowsAPI或DLL。
这是比较普遍的需求。一般来说,简单的函数调用,大可直接用C#/VB.NET,经过DllImport属性包装出函数来调用。如:
[DllImport("KERNEL32.DLL", EntryPoint="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为例吧,这样比较简单:
#include <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文件,就可以直接调用了:
wrapper.ApiWrapper.MoveFile(@"c:\debug.log", @"c:\debug.txt");
假如原有的代码是基于COM的,那么太好了,VisualStudio等IDE会自动生成一个用于包装的dll,供你调用。当然因特殊需要而手工编码的是另一回事。
场景三:现有C++原代码,包装后供C#调用。
C++的原代码,实际上可以直接编译成托管代码。MFC也好ATL也好……这样看起来在.NET中最强大的编程语言就是C++了:它不仅可以编写托管程序,甚至可以将标准C++的代码也编译成托管程序!其实VC++最强大的地方不止如此,它还在于能够编写混合了托管和非托管的代码的程序!!!这样最大的好处不仅可以将关键代码直接编译成非托管的代码,还可以避免被反编译。
假设现有C++代码如下:
class UnmanagedClass {
public:
LPCWSTR GetPropertyA() { return L"Hello!"; }
void MethodB( LPCWSTR ) {}
}; 我们只要再增加一个包装类到工程文件中: namespace wrapper
{
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++类了: ManagedClass mc = new ManagedClass();
mc.MethoB("Hello");
string s = mc.get_PropertyA;
场景四:如何在托管C++代码中混合托管和非托管代码
很简单,只要从#pragma unmanaged编译指示开始的程序,一率编译成非托管代码;要想恢复成托管代码,只要使用#pragma managed就可以了。如:
#pragma unmanaged
#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 函数: [PreserveSig, MethodImpl(MethodImplOptions.Unmanaged, MethodCodeType=MethodCodeType.Native), SuppressUnmanagedCodeSecurity]
public static unsafe void modopt(CallConvCdecl) f<char const *>(sbyte modopt(IsSignUnspecifiedByte) modopt(IsConst)*);
看不到源码,而方法属性标记为Unmanaged。
如果没有加上#pragma unmanaged,反编译得到的 f 函数为: internal 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等不好理解的类库,那么反编译出来的代码简直和源码没差别。
开心一刻:我只会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.转载自“http://ly4cn.teeta.com/blog/data/77172.html”
类别:程序设计 | 添加到搜藏 | 浏览(555) | 评论 (0) 上一篇:在C++中使用Google的“Protocol ... 下一篇:MSN跨站漏洞分析(转载) 最近读者: 登录后,您就出现在这里。
zhainx xuelianglv cherry_shining pangshapeng
分享到:
相关推荐
使用托管C++粘合C#和C++代码.pdf
简单易懂的代码,适用于新手,演示了c#如何通过托管c++全程调用c++
利用非托管C++编写加密性强的算法,然后利用托管C++包装,最后集成入C#中使用
C#调用C++编写的dll,一般都是直接用dllimport,这个资料很多。C++调用C#编写的dll,一般方法都是先用托管C++将C#的dll进行一次封装,然后由非托管C++调用封装好的dll。
目前支持最多8个参数,利用模版和多重继承机制实现的。
本人花费大量时间研究之作,虽然看起来挺简单的,但真的用了好长时间啊
附件是c#调用c++托管代码,最后调用c++ DLL代码。
因为业务需要学习C#调用C++的库 ...非托管 自己使用内存自己释放。 环境 VS2017 大致实现思路:首先创建C++项目 实现非托管动态库 ,其次在创建C++项目加载非托管运行库,发布成托管运行库,然后C#引用dll库。
1. 使用标准C++封装托管C++代码生成DLL供标准C++使用。 2. 有完整使用示例
在C#编程中,常会用到C++中的dll类库,简单介绍一下它们的对应关系。
Stanley B. Lippman关于如何从托管C++迁移到C++/CLI的说明。如果你在看VC技术内幕第6版,看到后面的托管C++部分,而现在的VC2005是使用新的C++/CLI语法的,那么,这份文档很合适。
Visual C++.NET托管扩展编程PDF,理念与范例相结合,全面介绍C++托管扩展.
这是本人刚用托管C++写的一个Excel导入程序,绝对能用!
在VS2010上使用C#调用非托管C++生成的DLL文件
C# 使用托管的方式调用C++ dll,实现简单的加减法
从C++到托管C++(C++/CLI)托管C++架起了一座标准C++通向.Net Framework的桥梁。
现在在Windows下的应用程序开发,VS.Net占据了绝大多数的份额。...下面就用一个完整的实例来详细说明怎样用托管C++封装一个C++类以提供给C#使用。 创建一个工程三个C#项目,托管C++项目和非托管C++项目。
演示如何在C#中调用非托管C++的类,是C#C++的混合编程技术的简单示例,VS2010开发
标准C++生成的动态链接库dll,在C#只能调用其方法,不能导出类。...此源码为首先用托管C++为媒介,将标准C++链接库封装成.net的dll,再由C#直接调用的例子。 源码保证能运行,希望对大家粘合C#和C++代码有帮助。