环境: VS2010 + Python27
DLL的创建过程参考: http://blog.csdn.net/cay22/article/details/5391319
1. 这里dll中导出函数是使用__stdcall声明的.
2. TestDll.dll中的两个导出函数
// TestDll.h
#pragma once #ifdef __cplusplus extern "C"{ #endif ///////////////////////////////////////////////////////////////////////////////////////////////////// struct STPerson { int m_nAge; char m_chName[50]; char* m_pDis; int m_nList[50]; }; int __stdcall GetSTPersonInfo(struct STPerson* pSTPerson); int __stdcall MyAdd(int nA, int nB); ///////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus } #endif
// TestDll.cpp
// TestDll.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include <iostream> #include <stdlib.h> #include "TestDll.h" #ifdef __cplusplus extern "C"{ #endif ///////////////////////////////////////////////////////////////////////////////////////////////////// int __stdcall MyAdd(int nA, int nB) { return nA + nB; } int __stdcall GetSTPersonInfo(struct STPerson* pSTPerson) { pSTPerson->m_nAge = 80; int i = 0; for(i = 0; i < 50; ++i) { pSTPerson->m_nList[i] = 2 * i; } strcpy(pSTPerson->m_chName, "Bluce"); pSTPerson->m_pDis = "const string"; return 1; } ///////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus } #endif
#-*- coding:utf-8 -*- import ctypes # 导出函数是__stdcall声明的使用 dll = ctypes.windll.LoadLibrary("TestDll.dll"); # 导出函数是__cdecl声明的使用 # dll = ctypes.cdll.LoadLibrary("TestDll.dll"); ret = dll.MyAdd(2, 4); print ret;
#-*- coding:utf-8 -*- import ctypes # 定义对应C++的数据结构 class STPerson(ctypes.Structure): _fields_ = [ ("m_nAge", ctypes.c_int), ("m_chName", ctypes.c_char * 50), ("m_pDis", ctypes.c_char_p), ("m_nList", ctypes.c_int * 50) ] # 导出函数是__stdcall声明的使用 dll = ctypes.windll.LoadLibrary("TestDll.dll"); # 导出函数是__cdecl声明的使用 # dll = ctypes.cdll.LoadLibrary("TestDll.dll"); # 最简单调用 ret = dll.MyAdd(2, 4); print ret; # 传递数据结构的调用 # 设置返回值类型 dll.GetSTPersonInfo.restype = ctypes.c_int; # 设置参数列表(每个参数的类型) dll.GetSTPersonInfo.argtypes = [ctypes.POINTER(STPerson)]; objectStruct = STPerson(); # 调用GetSTPersonInfo函数 nResult = dll.GetSTPersonInfo(ctypes.byref(objectStruct)); # 输出调用结果 print "m_nAge: ", objectStruct.m_nAge; print "m_chName: ", objectStruct.m_chName; print "m_pDis: ", objectStruct.m_pDis; for i, val in enumerate(objectStruct.m_nList): print 'm_nList[i]:', val; print nResult;
1. 这里主要是使用Python中的ctypes库
2. 在使用C++的数据结构时, Python一定要对应好, 说白了Python就是把数据结构的内存传递给DLL.
3. 所以要注意传递数据的内存对齐问题.
4. 对应C++的Python数据结构继承ctypes.Structure
5. 从上面代码可以看到, Python这样子调用DLL有一点脆弱哦, 随便一个类型没对上, 程序就会崩溃的.
6. 熟悉ctypes才能更好掌握Python调用DLL.
参考这个: https://docs.python.org/2/library/ctypes.html
7. ctypes和C的类型对应表
ctypes defines a number of primitive C compatible data types:
ctypes type | C type | Python type |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 1-character string |
c_wchar | wchar_t | 1-character unicode string |
c_byte | char | int/long |
c_ubyte | unsigned char | int/long |
c_short | short | int/long |
c_ushort | unsigned short | int/long |
c_int | int | int/long |
c_uint | unsigned int | int/long |
c_long | long | int/long |
c_ulong | unsigned long | int/long |
c_longlong | __int64 or long long | int/long |
c_ulonglong | unsigned __int64 or unsigned long long | int/long |
c_float | float | float |
c_double | double | float |
c_longdouble | long double | float |
c_char_p | char * (NUL terminated) | string or None |
c_wchar_p | wchar_t * (NUL terminated) | unicode or None |
c_void_p | void * | int/long or None |
4.1. 这里的调用dll是Python直接调用dll, 被调用的dll并不知道调用它的是什么语言.
4.2. Python有它自己的扩展框架, 我们可以按照Python规定的扩展框架来扩展Python的功能. 而这种扩展也是通过动态库实现(Window下是*.dll文件, Linux下是*.o文件)
4.3. 实现扩展功能的DLL与上面的DLL调用是有区别的, 扩展功能的DLL必须按照Python的扩展框架实现指定的接口(所以这个需要区分简单的dll调用).