一.直接调用c++的里面的方法
[DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int GetWindowLong(HandleRef hWnd, int nIndex);
其中,"user32.dll"为c++动态库名,EntryPoint指定C++方法名,CallingConvention 参数是c#调用c++的方式
其中CallingConvention.就有五种方式:
CallingConvention = CallingConvention.StdCall 使用StdCall调用匹配的Windows API
CallingConvention = CallingConvention.Cdecl 默认情况下,C和C++使用的Cdecl调用 ,
CallingConvention = CallingConvention.FastCall
CallingConvention = CallingConvention.ThisCall
CallingConvention = CallingConvention.Winapi
例子:
1、创建一个c++动态库项目
这个就不展开说了,网上的资料很多,不再叙述。
创建完成如图:
应用程序如果想要访问某个DLL中的函数,那么该函数必须是已经被导出来的函数。
现在我们打开CSharpInvoke.cpp,添加如下代码:
_declspec(dllexport) int add (int a, int b)
{
return a + b;
}
_declspec(dllexport) int subtract (int a, int b)
{
return a - b;
}
了让DLL导出函数,需要在每一个将要被导出的函数前面添加标识符:_declspec(dllexport)
编译生成文件,如图:
那么如何查看该DLL的函数已经被导出来了呢?我们使用vs自带的工具dumpbin。
在vs的安装文件中搜索”dumpbin.exe”,并为之设置为系统环境变量,这样我们就可以在任何文件下使用dumpbin命令了。
运行如下图:
可以看出来,我们的add和subtract是被导出来了,但是函数名前后多出了很多字符,这是因为c++编译器为了支持重载,所以在编译的时候给每一个接口都重新定义了唯一的名字,这个过程被称为“名字粉碎”。这个名字就是dll找到接口的入口地址。
4、c#应用程序调用dll
创建一个名叫start_cs的C#控制台程序。
填入如下代码:
public class CPPDLL
{
[DllImport("use_c++.dll",EntryPoint = "?add@@YAHHH@Z")]
public static extern int add(int x, int y);
[DllImport("use_c++.dll", EntryPoint = "?subtract@@YAHHH@Z")]
public static extern int subtract(int x, int y);
}
class Program
{
static void Main(string[] args)
{
int result = CPPDLL.add(10,20);
Console.WriteLine("10 + 20 = {0}", result);
Console.ReadLine();
}
}
意:EntryPoint后面跟着的是c++编辑器可以识别的函数入口,如果运行例子出现类似“……找不到程序入口”多半是没告诉编辑器能识别的接口名。