范例
就以md5為例吧,首先去github搜索md5,選一個用c或者c++寫的md5.
比如:https://github.com/chinaran/Compute-file-or-string-md5
我試了下用dev c++運行main_md5.c檔案沒什么問題,不過代碼中計算檔案md5的函式有點問題,先不管他,就演示一下計算字串的,
Dev c++
首先說一下怎么用dev寫一個dll
左上角->檔案->新建->專案

選擇DLL,下面選擇C專案,專案名隨便,就叫md5吧,然后選擇一個空檔案夾,即可創建dll專案
其他默認創建的dll.h檔案內容:
#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
#define DLLIMPORT __declspec(dllexport)
#else
#define DLLIMPORT __declspec(dllimport)
#endif
DLLIMPORT void HelloWorld();
#endif
這全部的代碼其實就一句__declspec(dllexport) void HelloWorld();,宣告HelloWorld函式并設定為匯出函式,
將上面github地址代碼下載下來,有三個檔案md5.h、md5.c、main_md5.c,
將這三個檔案中的內容稍微整合一下到dll.h、dll.c和dllmain.c中,后面給出下載鏈接
接著點上面的編譯運行,編譯完會彈出一個警告,沒有主程式,不用管它,看專案的目錄下的檔案,已經有個md5.dll了

這個就是要用其他語言呼叫的dll,以Python為例(注意修改dll路徑)
import ctypes
dll = ctypes.CDLL("D:\\Android\\aaaa\\md5.dll")
md5 = dll.Compute_string_md5
md5.argtypes=[ctypes.c_char_p, ctypes.c_uint, ctypes.c_char_p]
md5.restype = ctypes.c_int
msg = "123456"
result = ctypes.create_string_buffer(33)
print("運行是否成功(0成功):", md5(ctypes.c_char_p(msg.encode()), ctypes.c_uint(len(msg)), result))
print("字串: %s, md5: %s" % (msg, result.value.decode()))
運行一下成功得到結果:

另外需要注意的是,如果在64位系統上dev C++編譯的dll是64位的,需要使用64位Python才能呼叫,如果用的是32位則會報如下例外(32位dll同理)
Traceback (most recent call last):
File "d:/Android/md5/md5.py", line 14, in <module>
dll = ctypes.CDLL("D:\\Android\\aaaa\\md5.dll")
File "C:\Anaconda\envs\py32\lib\ctypes\__init__.py", line 369, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 不是有效的 Win32 應用程式,
百度了很久也沒有發現dev c++怎么在64位系統編譯32位dll,我試了直接更改右上角gcc的版本沒用,換成32位的會報錯,
代碼地址:https://gitee.com/kanadeblisst/dev-c-dll-md5/
vs2017
要想編譯32位的只能使用vs2017來編譯了, 怎么安裝就省略了,安裝vs2019也行,可能某些操作不太一樣,
左上角檔案->新建專案

選擇這個visual C++下的 Windows桌面下的具有匯出項的元件(記得修改上面的路徑,不然你都不知道去哪找專案檔案),如果沒有這個選項可能你功能沒有安裝完全,我安裝的時候是把Windows下的三個都勾選了,選擇的社區版,只需要登錄賬號即可使用,功能對我來說足夠用了,

代碼基本上一樣,復制到vs里就行了,就是不知道為什么他一定要pch.h這個頭檔案,改了名就報錯
我就直接將代碼復制到pch.h和pch.cpp了,另外還有個地方需要修改__declspec(dllexport) 前要加上extern “C” ,不然匯出函式的名字會變成其他了,前后加上了點東西(dev c++如果創建的是C++專案也是一樣的)
用32位Python試了下上面的Python代碼呼叫,沒啥問題,

vs默認編譯的是32位的dll,如果想編譯64位的直接將x86改成x64再點擊一次本地Windows除錯器生成的dll就是64位的了
同樣的代碼vs編譯的dll要比dev c++的小好多,到底是微軟自家的IDE,不過dev c++用來測驗一些簡單的c/c++代碼是真的方便,
代碼:https://gitee.com/kanadeblisst/vs2017-md5-dll
aardio呼叫dll
這個語言寫桌面程式非常方便,我用的很順手,就順便說說這個怎么呼叫dll,注意:aardio只能呼叫32的dll
import console;
var dll = raw.loadDll("D:\Android\Dll3\Debug\DLL3.dll",,"cdecl" );
var md5 = dll.api("Compute_string_md5","int(string str,int len, string str)");
var s = "12345";
var str = raw.buffer(33);
console.log("運行是否成功(0成功):", md5(s, #s, str))
console.log("md5結果: ", raw.tostring(str))
console.pause(true);
看著是不是和Python代碼差不了多少,步驟都是一樣的,加載dll->宣告函式原型->創建一個存放結果的緩沖區->呼叫函式->讀取緩沖區的值,
更新
編碼引發的小問題
md5 本身是對位元組進行操作的,那么對字串進行操作肯定要涉及編碼問題了,c語言在Windows的默認編碼是gbk,而Python3的默認編碼是utf-8,而我試了所有的網站,對字串計算md5用的編碼都是utf8,
修改也很簡單,可以不修改c代碼,直接修改Python呼叫dll時的代碼,只需要改傳入的第二個引數,上面的代碼用的是字串的長度,其實應該傳入位元組串的長度,修改代碼如下
md5(ctypes.c_char_p(msg.encode()), ctypes.c_uint(len(msg.encode())), result)
在python3中,'aaaa'.encode()等同于 'aaaa'.encode('utf-8'),所以并不需要更改編碼,反倒是在c語言中將gbk編碼變成utf8的很麻煩,
其實修改c代碼也很簡單,因為第二個引數長度是不必要的,可以直接通過第一個引數用strlen計算出來,所以在c代碼中改一下也行,strlen計算的長度是從開頭開始到遇到的第一個位元組0,即’\0’,正好是需要的長度,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/305458.html
標籤:python
下一篇:Python GUI編程
