WinPython 3.6.3でDLLの呼び出しの例を作成していた。
特に,DLLを読み込んだ後 後始末の部分が苦労した。
例1.普通に整数を引数にとり整数を戻す関数。
例2.文字列を引数にとる例。
例3.文字列を引数にとり渡した領域の一部を編集する例。
まず用意したDLLのサンプル(#ifdefの部分は本当は別のヘッダファイルに用意するものだが今回はCからは使わないのでここに書いている。すると_declspec(dllimport)はいらない)
// sampleDll0001.cpp : DLL アプリケーション用にエクスポートされる関数を定義します。 // // sampleDll0001.hの内容 #ifdef SAMPLEDLL0001_EXPORTS #define SAMPLEDLL0001_API extern "C" __declspec(dllexport) #else #define SAMPLEDLL0001_API extern "C" __declspec(dllimport) #endif #include "stdafx.h" #include "sampleDll0001.h" SAMPLEDLL0001_API int __stdcall fnsampleDll0001_01(int a, int b) { return a + b; } SAMPLEDLL0001_API int __stdcall fnsampleDll0001_02(char* a) { return (int)strlen(a); } SAMPLEDLL0001_API int __stdcall fnsampleDll0001_03(char* a) { if (strlen(a) > 5) { a[0] = 'a'; a[1] = 'b'; } return (int)strlen(a); }
次にPythonの部分。(Release/sampleDll0001.dllにファイルがあるとしている)
import ctypes from ctypes import wintypes lib = ctypes.windll.LoadLibrary("Release/sampleDll0001.dll"); a = lib.fnsampleDll0001_01(ctypes.c_long(1), ctypes.c_long(2)); print(a); string1 = "my string 1" b_string1 = string1.encode('utf-8') a = lib.fnsampleDll0001_02(b_string1); print(a); string2 = "my string 2" b_string2 = string2.encode('utf-8') a = lib.fnsampleDll0001_03(ctypes.c_char_p(b_string2)); string2 = b_string2.decode('utf-8') print(string2); libHandle = lib._handle del lib kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) kernel32.FreeLibrary.argtypes = [wintypes.HMODULE] kernel32.FreeLibrary(libHandle)
ctypes.windllはstdcallの場合らしい。
cyptesでは簡単にdllの読み出しができるようになったが,読み終わった後で開放してくれない。
それに対して,kernel32.dllのFreeLibrary()を使用すればよいのだが,x86用は良いのだが,x64は宣言が間違っているらしい。
ctypes.windll.kernel32.FreeLibrary(libHandle)
ctypes.ArgumentError: argument 1: <class 'OverflowError'>: int too long to convert
と表示されてしまう。kernel32.FreeLibrary.argtypesを代入しなおして間違いを訂正する必要があるらしい。