VS2017编写纯C库以及使用C#调用C库方法

原博主博客地址:https://blog.****.net/qq21497936
本文章博客地址:https://blog.****.net/qq21497936/article/details/83825098

 

            VS2017编写纯C库以及使用C#调用C库方法

 

Demo源码下载

      https://download.****.net/download/qq21497936/10770528

 

建立C库

使用VS2017建立Visual C++ Dll空项目

打开VS2017建立Visual C++桌面向导,如下图:

VS2017编写纯C库以及使用C#调用C库方法

点击确认后,开始向导创建工程,如下图:

VS2017编写纯C库以及使用C#调用C库方法

点击“确认”,工程目录,如下图:

VS2017编写纯C库以及使用C#调用C库方法

 

创建库源码,并生成C库

添加头文件(cDllDemo.h)与源文件(cDllDemo.cpp)

VS2017编写纯C库以及使用C#调用C库方法

定义变量和函数宏定义

VS2017编写纯C库以及使用C#调用C库方法

实现函数源码

VS2017编写纯C库以及使用C#调用C库方法

编译生成动态库

VS2017编写纯C库以及使用C#调用C库方法

添加回调函数

C库头文件添加(回调函数的全局变量指针和设置回调函数的函数)

VS2017编写纯C库以及使用C#调用C库方法

C库源文件添加

VS2017编写纯C库以及使用C#调用C库方法

解决被调用时可能无法查看到printf打印信息

VS2017编写纯C库以及使用C#调用C库方法

 

winform以及wpf使用C库

创建wpf工程(winform工程调用也是一样)

VS2017编写纯C库以及使用C#调用C库方法

设置依赖项,为了每次运行该测试应用之前,先编译生成对应的dll,方式dll修改未更新,如下图:

 

VS2017编写纯C库以及使用C#调用C库方法

VS2017编写纯C库以及使用C#调用C库方法

填入测试代码

VS2017编写纯C库以及使用C#调用C库方法

运行时出现如下报错,调用不带输入参数的不报错,输入参数的签名对不上(就是函数定义);

VS2017编写纯C库以及使用C#调用C库方法

此时我们修改c#调用方式,如下图:

VS2017编写纯C库以及使用C#调用C库方法

运行结果:

VS2017编写纯C库以及使用C#调用C库方法

使用C库中的全局变量

       在c中把全局变量的读写封装成函数,c#通过P/Invoke来调用函数(理解为set和get),修改c库头文件内容如下:

VS2017编写纯C库以及使用C#调用C库方法

源文件如下:

VS2017编写纯C库以及使用C#调用C库方法

       修改wpf程序如下:

VS2017编写纯C库以及使用C#调用C库方法

运行结果如下:

VS2017编写纯C库以及使用C#调用C库方法

使用C库中的回调函数

       首先,在C库头文件和源文件中定义回调函数全局变量和回调函数,如下图:

VS2017编写纯C库以及使用C#调用C库方法

       在c#中回调步骤:1定义委托->2引入C库函数->3定义静态委托函数->4定义委托变量->5设置委托

VS2017编写纯C库以及使用C#调用C库方法

在C#中若出现直接挂掉(当前项目中,若当机无异常或者无已停止运行,目前所知都是调用的C库挂掉的,从C库找原因),特别注意委托函数需要加上调用的方式,是Cdecl不是StdDecl,如下图:

VS2017编写纯C库以及使用C#调用C库方法

       如果不写该项,则表示委托定义默认为StdDecl,读者可自行尝试,会跑完会后会直接挂掉,示意如下图:

VS2017编写纯C库以及使用C#调用C库方法

理解[UnmanagedFunctionPointer(CallingConvention.Cdecl)]

  1. UnmanagedFunctionPointer:表示动态使用未托管的dll函数指针;
  2. CallingConvention.Cdecl:C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀,是MFC缺省调用约定;
  3. CallingConvention.StdDecl:__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。_stdcall是Pascal程序的缺省调用方式,通常用于Win32Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数;

c库打印信息问题

C库添加打印语句

VS2017编写纯C库以及使用C#调用C库方法

运行的代码

 

VS2017编写纯C库以及使用C#调用C库方法

VS2017编写纯C库以及使用C#调用C库方法

关闭应用后打印出来:

VS2017编写纯C库以及使用C#调用C库方法

解决被调用时可能无法查看到printf打印信息

需要重定向输出,使用setbuf函数,如下图:

VS2017编写纯C库以及使用C#调用C库方法

VS2017编写纯C库以及使用C#调用C库方法

不能在运行时,每次调用,所以我们优化一下,定义一个初始化函数,修改库的头文件和源文件如下:

VS2017编写纯C库以及使用C#调用C库方法

 

 

原博主博客地址:https://blog.****.net/qq21497936
本文章博客地址:https://blog.****.net/qq21497936/article/details/83825098