1. 先新建一個名為 hello.cpp 的 C++ 源文件:
Cpp代碼
#include <stdio.h>
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT int __stdcall hello()
{
printf("Hello world!\n");
return 0;
}
#include <stdio.h>
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT int __stdcall hello()
{
printf("Hello world!\n");
return 0;
}
2. 編譯成 dll 文件:
Cpp代碼
cl /LD hello.cpp
cl /LD hello.cpp
注意, 這裡的參數是 /LD, 而不是 /DL。
3. 編寫一個名為 hello.py 的 python 文件:
Python代碼
# 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()
# 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. 輸出為:
Python代碼
starting...
Hello world!
starting...
Hello world!
需要注意的地方:
1. C++ 的 dll 中的接口函數必須以 extern "C" __declspec(dllexport) 為前綴, C 的以 __declspec(dllexport) 為前綴。
否則會報錯:
Python代碼
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
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 www.2cto.com
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.