如何用 C++ 爲 Python 寫 dll

1. 先新建一個名爲 hello.cpp 的 C++ 源文件:php

Cpp代碼 複製代碼  收藏代碼
  1. #include <stdio.h>   
  2.   
  3. #define DLLEXPORT extern "C" __declspec(dllexport)   
  4.   
  5. DLLEXPORT int __stdcall hello()   
  6. {   
  7.     printf("Hello world!\n");   
  8.     return 0;   
  9. }  
#include <stdio.h>

#define DLLEXPORT extern "C" __declspec(dllexport)

DLLEXPORT int __stdcall hello()
{
    printf("Hello world!\n");
    return 0;
}
 


2. 編譯成 dll 文件:
python

Cpp代碼 複製代碼  收藏代碼
  1. cl /LD hello.cpp  
cl /LD hello.cpp
 


注意, 這裏的參數是 /LD, 而不是 /DL。


3. 編寫一個名爲 hello.py 的 python 文件:
windows

Python代碼 複製代碼  收藏代碼
  1. # coding: utf-8   
  2.   
  3. import os   
  4. import ctypes   
  5.   
  6. CUR_PATH = os.path.dirname(__file__)   
  7.   
  8. if __name__ == '__main__':   
  9.     print 'starting...'  
  10.     dll = ctypes.WinDLL(os.path.join(CUR_PATH, 'hello.dll'))   
  11.     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代碼 複製代碼  收藏代碼
  1. starting...   
  2. Hello world!  
starting...
Hello world!

 


須要注意的地方:
1. C++ 的 dll 中的接口函數必須以 extern "C" __declspec(dllexport) 爲前綴, C 的以 __declspec(dllexport) 爲前綴。
不然會報錯:ui

 

Python代碼 複製代碼  收藏代碼
  1. Traceback (most recent call last):   
  2.   File "hello.py", line 12in <module>   
  3.     dll.hello()   
  4.   File "C:\Python25\lib\ctypes\__init__.py", line 361in __getattr__   
  5.     func = self.__getitem__(name)   
  6.   File "C:\Python25\lib\ctypes\__init__.py", line 366in __getitem__   
  7.     func = self._FuncPtr((name_or_ordinal, self))   
  8. 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

 


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

相關文章
相關標籤/搜索