1. 先新建一个名为 hello.cpp 的 C++ 源文件:php
#include <stdio.h> #define DLLEXPORT extern "C" __declspec(dllexport) DLLEXPORT int __stdcall hello() { printf("Hello world!\n"); return 0; }
2. 编译成 dll 文件:
python
cl /LD hello.cpp
注意, 这里的参数是 /LD, 而不是 /DL。
3. 编写一个名为 hello.py 的 python 文件:
windows
# coding: utf-8 import os import ctypes CUR_PATH = os.path.dirname(__file__) if __name__ == '__main__': print 'starting...' dll = ctypes.WinDLL(os.path.join(CUR_PATH, 'hello.dll')) dll.hello()
4. 输出为:函数
starting... Hello world!
须要注意的地方:
1. C++ 的 dll 中的接口函数必须以 extern "C" __declspec(dllexport) 为前缀, C 的以 __declspec(dllexport) 为前缀。
不然会报错:ui
Traceback (most recent call last): File "hello.py", line 12, in <module> dll.hello() File "C:\Python25\lib\ctypes\__init__.py", line 361, in __getattr__ func = self.__getitem__(name) File "C:\Python25\lib\ctypes\__init__.py", line 366, in __getitem__ func = self._FuncPtr((name_or_ordinal, self)) AttributeError: function 'hello' not found
2. 是使用 ctypes.CDLL 仍是 ctypes.WinDLL 呢?
反正我是分不清,因此在 dll 中的接口函数中显式地加上了 __stdcall. 彷佛一个是 caller 清栈,另一个是 callee 清。
MSDN 中关于 __stdcall, __cdecl 的介绍:
__cdecl:
http://msdn.microsoft.com/en-us/library/zkwh89ks(VS.80).aspx
This is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code. The following list shows the implementation of this calling convention.
__stdcall:
http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.71).aspx
The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl.
参考文档:
1. 《How to write a DLL/SO in C/C++ for Python》
http://wolfprojects.altervista.org/dllforpyinc.php
2. 《Python调用windows下DLL详解 - ctypes库的使用》
http://blog.csdn.net/magictong/archive/2008/10/14/3075478.aspx
this