PythonからDLLを使う


はじめに

あることから、PythonでC++で作られたDLLを読み込みたいので調べる必要が出てきました。
私自身PythonもC++もさわり程度しか知らないため、少しハマりました。
様々な記事が既に世の中に存在していますが、自分のために書き残そうと思います。

まずDLLを準備

VS2017 使用しています。
ダイナミックリンクライブラリのプロジェクトを作成。名前は何でもいいと思います。
今回はDLLTestという名前で作っています。

DLLプログラムを作っていきます

DLLTest.h
#pragma once

#ifdef DLLTEST_EXPORTS
#define DLLTEST_API extern "C" __declspec(dllexport)
#else
#define DLLTEST_API extern "C" __declspec(dllimport)
#endif // DLLTEST_EXPORTS

DLLTEST_API int GetData(int, int);

extern "C" __declspec(dllexport)で、関数のエクスポート宣言をします。

DLLTest.cpp
// DLLTest.cpp : DLL アプリケーション用にエクスポートされる関数を定義します。
//

#include "stdafx.h"
#include "DLLTest.h"

int GetData(int a, int b)
{
    return a + b;
}

実行する関数を作っていきます。

stdafx.h
// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、
// または、参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // Windows ヘッダーからほとんど使用されていない部分を除外する
// Windows ヘッダー ファイル
#include <windows.h>
#include <string>


// プログラムに必要な追加ヘッダーをここで参照してください
#include "DLLTest.h"

はい、以上です。ハマりどころは後述します。先に成功パターンで。
Debugビルドを行ってDLLを作成します。DLLはプロジェクトの中のDebugフォルダの中にあります。

次にPython側で呼び出し

PCにはPython 3.7と2.7がインストールされていますが、3.7を今回利用しています。
VS2017で作ったDLLをpythonのソースの場所へコピーしてきます。
そして、LoadLibraryにDLL名をセットします。

test.py
# coding: utf-8

from ctypes import *

dll = cdll.LoadLibrary("DLLTest.dll")

print(dll.GetData(100, 101))

これで、Pythonを実行すると。DLLで結果を出すことができました。

> py test.py
201

ハマったところ

「OSError: [WinError 193] %1 は有効な Win32 アプリケーションではありません。」と出た。

解決
DLLのビルドがx64ではなかった。Pythonを64ビットでインストールしてたため。気づくのに少し時間かかりました。。

「AttributeError: function 'GetData' not found」と出た。

解決
extern "C"が抜けていた。

DLLTest.h
#define DLLTEST_API extern "C" __declspec(dllexport)

いろいろ勉強になりました。