C#中调用C++编写的Dll

C#调用C++ Dll

1、用C++生成Dll

      在VS2013中创建一个Win32控制台项目,单击下一步,然后选择Dll。

C#中调用C++编写的Dll_第1张图片

      生成的工程目录结构为:

C#中调用C++编写的Dll_第2张图片

      在自动生成的文件中,dllmain.cpp作为定义DLL应用程序的入口点,它的作用跟exe文件有个main或者WinMain入口函数是一样的。可以在目标cpp文件(dllcxj.cpp)中编写自己要实现的函数。

C#中调用C++编写的Dll_第3张图片

2、C#中调用.dll库中的函数:

      在C#中新建一个类(Cppdll.cs),引用对应的dll:

      [DllImport("D:\\ConsoleApplication1\\bin\\dllcxj.dll")]

      public static extern string GetString();

C#中调用C++编写的Dll_第4张图片

      注意:需要在程序声明中使用System.Runtime.InteropServices命名空间。

      DllImport作为C#中对C++的DLL类的导入入口特征,只能放置在方法声明上,并通过static extern对extern “C”进行对应。在需要的地方调用.dll中的函数:直接使用类调用静态方法,如:string s = Cppdll.GetString();

3、C++中的函数修饰参数的含义:

      extern "C" __declspec(dllexport) int__stdcall Add(int x, int y)

      {

       ···

      }

extern ”C”:

      通常来说,C++编译器可能会改变函数和变量的名字,从而导致严重的链接程序问题。例如,假设使用C++编写一个DLL,当创建DLL时,Microsoft的编译器就会改变函数的名字。函数名将被设置一个前导下划线,再加上一个@符号的前缀,后随一个数字,表示作为参数传递给函数的字节数。例如,下面的函数是作为DLL的输出节中的_MyFunc@8输出的:

            __declspec(dllexport)LONG __stdcallMyFunc(int a,int b);

      如果用另一个供应商的工具创建了一个可执行模块,它将设法链接到一个名叫MyFunc的函数,该函数在Microsoft编译器已有的DLL中并不存在,因此链接将失败。使用extern “C”关键字可以使编译器按照C语言的方式编译DLL文件,即编译时不改变函数名。

__declspec(dllexport)

       __declspec(dllexport)的目的是为了将对应的函数放入到DLL动态库中。在 32位编译器版本中,可以使用__declspec(dllexport) 关键字从DLL导出数、函数、类或类成员函数,__declspec(dllexport) 会将导出指令添加到对象文件中,因此不需要使用.def文件。若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。

__stdcall:表明被调用方清理堆栈。

4、C#中DllImport的相关参数:

using System.Runtime.InteropServices;

  System.Runtime.InteropServices命名空间提供各种各样支持 COM interop 及平台调用服务的成员,使程序可以与非托管代码进行交互操作。

[DllImport("dllfilepath")]

  代码中DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在这个类中。DllImportAttribute 属性包括:

       DllfilepathDllfilepath要求写为静态常量,因此不方便使用表达式表示dll的路径,而直接写Dll的绝对路径又不方便程序的移植。推荐直接写dll的名称加后缀名,如:"XX.dll"。DllImport会按照顺序自动去寻找的地方: 1、exe所在目录 2、System32目录 3、环境变量目录。所以只需要把引用的DLL 拷贝到上述任意一个目录下即可。 不用写.dll绝对路径。

       EntryPoint="MessageBoxA"使用EntryPoint属性设置函数名

       CharSet 指示用在入口点中的字符集,如:CharSet=CharSet.Ansi;

       SetLastError 指示方法是否保留 Win32"上一错误",如:SetLastError=true;

       ExactSpelling 指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配,如:ExactSpelling=false;

       PreserveSig指示方法的签名应当被保留还是被转换,如:PreserveSig=true;

       CallingConvention指示入口点的调用约定,如:CallingConvention=CallingConvention.Winapi;建议增加特性 CallingConvention=CallingConvention.Cdecl,不然可能会出现 “堆栈不对称”错误。必须在标记为”static”和”extern”的方法上指定”DllImport”属性,每一个方法前面都需要添加DllImport。

你可能感兴趣的:(dll)