1. 程式人生 > >1.Python呼叫C語言之如何呼叫動態連結庫

1.Python呼叫C語言之如何呼叫動態連結庫

平時用C&C++和Python比較多,喜歡鼓搗點小玩意兒。之前在《數學之美》這本書裡面看見布隆過濾器這個東西,簡直是爬蟲利器!所以當時用C++寫了一個簡單的,後來封裝成了動態連結庫拿來給爬蟲用大笑。所以就研究了一下怎麼用Ptython呼叫C語言,寫個博文記錄一下!

Python呼叫C語言需要動態連結庫的形式,而Python呼叫動態連結庫則需要ctypes這個模組。

首先我們看看ctypes裡面有些神馬東西,怎麼看呢?當然是神奇的dir()函式。

import ctypes
print '\n'.join(dir(ctypes))
大家可以自己把上面程式碼進去執行檢視。

首先要講的是3個東東,CDLL、windll和oledll。在dir裡面,我們會發現一個奇怪的東西,既有Windll又有WINDLL。免得混淆,索性都看看吧。


嗯,就是這樣,CDLL、windll和oledll是三個Class。而OleDLL和WinDLL是2個type(PS:類,型別,傻傻分不清楚?Google it)

這3個Class的區別是它們呼叫的方法和返回值。CDLL載入的庫是標準C語言的cdecl。windll載入的庫是必須使用stdcall的呼叫約定。oledll和windll差不多,不過會返回一個HRESULT錯誤程式碼,使用COM函式可以獲取具體資訊.(這一坨來自一本叫做《python灰帽子》的書)

最後,看看例項吧。

首先看看CDLL的,就用那個布隆過濾器啦。

Example1:

首先附上DLL程式碼,一個很簡單的布隆過濾器,來自某部落格,被我改了改難過

#include "stdafx.h"
#include <iostream>
#include <bitset>
#include <string>
using namespace std;

#define DLLAPI extern "C" _declspec(dllexport)
const long MAX= 2<<24;
bitset<MAX> bloomset;
int seeds[7]={3,7,11,13,31,37,61};
int getHash(char* str,int n)
{
	int result=0;
	for (int i=0;i<strlen(str);i++)
	{
		result=seeds[n]*result+(int)str[i];
		if(result > 2<<24)
			result%=2<<24;
	}
	return result;
}

DLLAPI void Dir()
{
	cout<<"bool isInBloomSet(char* str)"<<endl;
	cout<<"bool addBloomSet(char* str)"<<endl;
}
DLLAPI int isInBloomSet(char* str)
{
	for ( int i=0;i<7;i++ )
	{
		int hash=getHash(str,i);
		if(bloomset[hash]==0)
			return 0;
	}
	return 1;
}

DLLAPI bool addBloomSet(char* str)
{
	for(int i=0;i<7;i++)
	{
		int hash=getHash(str,i);
		bloomset.set(hash,1);
	}
	return true;
}

python程式碼
from  ctypes import *
dllpath='C:\\Users\\***\\Documents\\Visual Studio 2010\\Projects\\BloomFiliter\\Release\\BloomFiliter.dll'
url=[c_char_p('www.baidu.com'),c_char_p('www.google.com')]
bloom=CDLL(dllpath)
bloom.Dir()
print bloom.addBloomSet(url[0])
print bloom.isInBloomSet(url[0])
print bloom.isInBloomSet(url[1])
print ''
x=raw_input()

Exmaple2:

from ctypes import *
msvcrt = cdll.msvcrt
str = "hahahahah!"
msvcrt.printf("Hello %s\n", str)
x=raw_input()

再看看windll的用法吧,直接調MessageBox牛不牛逼大笑

from ctypes import *;
MessageBox = windll.user32.MessageBoxW
test=c_wchar_p("Great")
title=c_wchar_p("Hello World")
MessageBox(0,test,title, 0)
當然windll可以用LoadLibrary其他符合呼叫約定的DLL,大家可以試試。

OleDLL具體方法一樣,大家有空試試吧。