日期:2011-04-30  浏览次数:20497 次

在C#中使用C/C++写的DLL

呵呵..,又到了我有想写点东西的时候了.最近在论坛老是看见有朋友问

C/C++的程序如何在C#中使用?其实这是个很不错的想法.代码复用.不过

托管程序如何使用非托管代码呢?想想看,很自然就联想到了DLL动态连接库

把C/C++的代码编译成DLL,然后使用,这里我假设我的C/C++代码里包含一个

函数,叫average(int av[])

申明如下:
extern "C" __declspec(dllexport) __cdecl int average(int *av);

实现嘛就更简单了
__declspec(dllexport) __cdecl int average(int av[])
{
int i=0;
int sum=0;
  while(av)
{
  sum+=av[i];
   i++;
}
return sum/i;
}//随手写的也许有点问题

好了不管那么多,让我们来看看C#的代码是如何实现的,我想你应该想的到

是什么?猜猜看,OK,我想你至少能想到两个英文单词dll import,是的你猜对了

DLLImport 属性,就是它,看看它有些什么,我可以用到,MSDN是最好的选择.看见了吗

是的,准确地说,DllImport 属性具有下列行为:

它只能放置在方法声明上。

它具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。

它具有五个命名参数:
 

CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值
CallingConvention.Winapi。

CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。

EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。

ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定
ExactSpelling,则使用默认值 false。

PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有
HRESULT 返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使
用默认值 true。

SetLastError 参数指示方法是否保留 Win32“上一错误”。如果未指定 SetLastError,则使用默认值

false。

它是一次性属性类。

此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。

是的,上面就是MSDN原文内容.好了继续我们的例子,好了,先把我们上面的C代码编译成DLL

叫什么呢?那就叫MYDLLTest好了.

[DllImport("MYDLLTest.dll",EntryPoint="average",ExactSpelling=false,CallingConvention=CallingConvention.Cdecl)]
static extern int average(int av[]);

好了,该是你找个地方写一句的时候了

如:

int[5] i={1,2,3,4,5};
int j=average(i);


好了,你看到了,就是这样的,可是事实上并没有你想的那么简单.因为设计到很多问题

你看上面的例子中,int是在C#和C/C++中都有的,可是如果是char *呢?也许你会说string

可是你看在C/C++中这些都表示字符串(char*,or wchar_t*,or BSTR, ..)那我们该怎么办?

想想看,还有些什么?属性吗?是的,找找,对了我似乎想到一个单词.Marshal恩..记得它吗?

别告诉我,你会把它拼成马歇尔.哈哈..开个玩笑是列集.我们在MSDN上输入看看找到什么了?

是的MarshalAs.看看MSDN上说些什么?"指示应如何在托管代码和非托管代码之间封送数据"

哈哈.看来不错呢.在看看下面的备注:

可将该属性应用于参数、字段或返回值。

该属性为可选属性,因为每个数据类型都有默认的封送处理行为。仅在可以将给定类型封送到多个类型时需要此属性。例如,String 可能作为 LPStr、LPWStr、LPTStr 或 BStr 封送到非托管代码。默认情况下,字符串作为 BStr 封送到 COM 方法。可将 MarshalAsAttribute 属性应用于个别的字段或参数,以使该字符串作为 LPStr 而非 BStr 封送。有关如何使用此属性的完整详细信息,请参阅“数据封送处理规范”。

大多数情况下,该属性只是使用 UnmanagedType 枚举标识非托管数据的格式,如下面的示例所示。

[C#]
void MyMethod([MarshalAs(LPStr)] String s);
某些 UnmanagedType 枚举需要附加信息。例如,当 UnmanagedType 为 LPArray 时需要附加信息。有关如何使用此属性的完整说明,请参阅“数据封送处理规范”。

瞧见了,正是我们需要的对吗?好了,我就写怎么多了,事实上,还有关于结构(struct)的

这就需要,你来完成了.希望对你有点帮助.(完)