最近在做一个项目的时候遇到这样一个问题,需要为设备商提供的程序提供一些可调用的函数用于扩展其功能,供应商的程序使用早期的delphi 6编写,最好的办法就是把这些功能函数封装为普通的windows DLL,但是这些功能和另外一个已经完成的项目可以重用,唯一的问题就是那个项目是用C#编写的,从非托管代码是不能直接使用这些托管对象类型的。我们知道托管DLL文件的PE格式除了普通PE文件的格式外,更多的是IL代码和元数据,IL代码是要在CLR中由JIT编译成本CPU的指令集的指令来运行的,所以是不能直接象使用普通windows DLL那样装载使用托管dll的。
一种办法是把托管类包装为COM对象,在MSDN有介绍如何来操作:,这种办法颇为麻烦,个人也不太喜欢COM的操作方式,那么还有其他的办法吗?这就是使用托管VC++做一个中间过渡的DLL。下面以一个普通windows控制台程序调用显示.net的一个form为例来简单看看是如何实现的。
首先创建一个C#的Class library工程clrform,往工程中添加一个form:
namespace clrform{ public partial class MyForm : Form { public MyForm() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { MessageBox.Show("Message from .net form."); this.DialogResult = DialogResult.OK; } public int ShowMe() { if (this.ShowDialog() == DialogResult.OK) return 1; return 0; } }}
再创建一个visual c++的clr class library项目clrdll来包装.net form,visual studio会自动添加clr支持,在reference中添加前面的模块clrform,主要的代码类似:
extern "C" __declspec(dllexport) int __stdcall ShowMyForm(){ clrform::MyForm^ myform=gcnew clrform::MyForm(); return myform->ShowMe();}
最后来创建一个win32的控制台程序来调用clrdll的ShowMyForm:
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){ int nRetCode = 0; // initialize MFC and print and error on failure if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { _tprintf(_T("Fatal Error: MFC initialization failed\n")); nRetCode = 1; } else { int i=ShowMyForm(); std::cout<
整个过程就是这样的简单了,这里没有参数的传递,在实际的例子中还需要注意参数的类型转换,比如从.net的string到mfc的CString等等。
另外.net SDK也提供CLRCreateInstance(在MSCorEE dll中实现)来创建和宿主自己的CLR,在这个CLR中手工装载和运行程序集。
在codeproject上有一篇文章更加详细全面的讲述了通过vc++ clr和托管代码的互操作: