最近有个项目需要使用到python来调用C++编写动态连接库
无奈在百度上的办法百花齐放
跟着做也频频出错
所以自己研究了一下调用的规则
————————————下面是正文——————————————
一.环境描述
首先说明下编译的环境:C++编译环境是 —>VS2015、python编译环境是 —> pycharm
二.C++编写DLL
在编写动态库之前,我们要先明确所编写的DLL是32bit还是64bit的,博主当时就是因为pycharm是64位的而DLL是32位的而调用失败,细节决定成败......确定好之后,先新建一个 “WIN32项目”
点击确定之后进而按照以下图示进行选择,当然,也可以不创建一个空项目,只是博主喜欢啥都是自己写的,这样比较有安全感,有兴趣可以研究下其他方式:
之后在创建一个.cpp以及.h头文件,具体怎么创建我就不在此描述,如何不知道怎么创建的话,自行百度:
创建完文件之后,我们先对头文件(Sum.h)进行编写:
#include <iostream>
#define Export extern "C" _declspec(dllexport)
Export int _stdcall SumTest(int a, int b);
在此处,我们首先来了解下几个关键字的使用:
1. extren "C" : 使用该关键字在于C++的编译器会对符号进行修饰,导出的 _declspec(dllexport/dllimport) function(void ,void) 函数会被改编为 _declspec(dllexport/dllimport) function _void,_void ,此举将给编译器取得函数的地址带来不便,所以,使用 extren "C" 来限定函数根据C的方式进行编译,防止出现符号修饰。
2._declspec(dllexport/dllimport) : 用于Windows中动态库中,用于将函数或者类声明为导出函数(dllexport)/导入函数(dllimport),以供其他程序调用。
3. _stdcall :该关键字属于C/C++ 的调用约定中的一种,调用约定决定了:A.函数压栈的顺序 B.产生修饰名的方式 C.决定了函数的参数由调用者还是被调用者push出栈,想要了解更多的调用约定的知识可自行百度,在此不再累述。使用调用约定绝大多数并不会影响到程序的逻辑,但是如果对于跨语言进行编程时,则现得十分重要,每个编译器所默认的调用约定都不一样,VC/VS 默认 _cdecl 的方式,Windows API 默认 _stdcall 的方式,所以在编写DLL时,为了与Windows API保持一致,一般使用 _stdcall 的调用约定。
编写完头文件之后,再编写源文件(Sum.cpp):
#include "Sum.h"
Export int _stdcall SumTest(int a, int b)
{
return a + b;
}
在写完测试函数之后 “ 生成解决方案 ” ,等待片刻即可生成一个后缀为.dll 的动态库文件(注意,在生成解决方案时记得查看生成的文件是32bit 还是64bit 的):
将图示框住的动态库文件复制粘贴到新建的python目录下:
然后编写python的调用代码:
from ctypes import *
dll = WinDLL('DLLTest.dll')
a = c_int(3)
b = c_int(4)
print(dll.SumTest(a,b))
注意:如果DLL中使用的 _stdcall 调用约定,在python中需要使用 windll.LoadLibrary()/WinDll() 进行调用;
如果DLL中使用的 _cdecl 调用约定,在python中需要使用 CDll() 进行调用;
其他调用约定的导入方式可自行百度~
编写完代码之后进行编译,编译成功: