C# 调用 C++ DLL(1) 非托管方式:直接调用C++方法

一.直接调用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++动态库项目

这个就不展开说了,网上的资料很多,不再叙述。

创建完成如图:

这里写图片描述

2、生成基于c++的dll文件

应用程序如果想要访问某个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命令了。

运行如下图: 
这里写图片描述

可以看出来,我们的addsubtract是被导出来了,但是函数名前后多出了很多字符,这是因为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++编辑器可以识别的函数入口,如果运行例子出现类似“……找不到程序入口”多半是没告诉编辑器能识别的接口名。

猜你喜欢

转载自blog.csdn.net/stwuyiyu/article/details/81197777