ブログ

割とコンピュータよりの情報をお届けします。

2018年8月18日

WinPython でDLLの読み出し例の作成

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を代入しなおして間違いを訂正する必要があるらしい。

≫ 続きを読む

2018/08/18 コンピュータ   TakeMe