Visual Studio Express 2017 for Windows Desktopで作るアプリ(Visual C++プロジェクトで作るアプリ)からPythonの関数を呼び出すという例を作成していた。ただし,今回はWinPython-64bit-3.6.3.0Qt5の場合である。
Pythonの関数の側
まず,Pythonの関数の側を用意してみました。内容は,引数として文字列を受け取り,文字列を返す関数です。この例では,この関数の記述をしたファイルをtest.pyとして実行ファイルと同じファイルにおくように用意しました。
def fnc(msg): msg2 = msg + 'ehe' + msg print(msg); return msg2
C++/C言語のプログラムの側
Visual Studioで新しいプロジェクトとしてVisual C++のプロジェクトを作成します。C++/C言語のプログラムの側の中身をご紹介します。
#include <Python.h> int main() { PyObject *pName, *pModule, *pFunc; PyObject *pArgs, *pArg, *pValue; Py_Initialize(); pName = PyUnicode_DecodeFSDefault("test"); pModule = PyImport_Import(pName); Py_DECREF(pName); if (pModule != NULL) { pFunc = PyObject_GetAttrString(pModule, "fnc"); if (pFunc && PyCallable_Check(pFunc)) { pArgs = PyTuple_New(1); // 関数fncの引数の数を引数にする pArg = PyUnicode_FromString("test"); if (!pArg) { Py_DECREF(pArgs); Py_DECREF(pModule); } PyTuple_SetItem(pArgs, 0, pArg); // 2nd argument is the position of the positional argument pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); if (pValue != NULL) { printf("return: %s\n", (char*)PyUnicode_DATA(pValue)); Py_DECREF(pValue); } else { Py_DECREF(pFunc); Py_DECREF(pModule); PyErr_Print(); fprintf(stderr, "Call failed\n"); return 1; } } else { if (PyErr_Occurred()) PyErr_Print(); fprintf(stderr, "Cannot find function\n"); } Py_XDECREF(pFunc); Py_DECREF(pModule); } else { PyErr_Print(); fprintf(stderr, "Failed to load module\n"); return 1; } if (Py_FinalizeEx() < 0) { return 120; } return 0; }
ビルドの方法
Python.hはWinPythonのインストールディレクトリのpython-3.6.3.amd64\includeにある。 python36.libはE:\WinPython-64bit-3.6.3.0Qt5\python-3.6.3.amd64\libsにある。これらはプロジェクトのプロパティで設定する必要がある。 いまのところDebug構成の場合,リンクの入力にpython36.libを指定していてもpython36_d.lib(デバッグ用)をリンクしようとしてしまうらしいので,うまく使えない。
WinPythonの場合にはデバッグ用のpython36_d.lib/python36_d.dllを作成するにはソースからビルドすることになってしまいかなり面倒である。
したがって,Debug構成とRelease構成を見分けている_DEBUGという定義を一時的にでも消す方法もある。
#ifdef _DEBUG #undef _DEBUG #include <Python.h>#define _DEBUG #else #include <Python.h> #endif
実行
WinPython Command Prompt.exeでコマンドプロンプトを開き,Visual Studioがわでビルドしてできたファイルをx64\Releaseに見つける。そして上で用意したtest.pyを同じディレクトリにコピーして。
set PYTHONHOME=<WinPythonインストールディレクトリ>\python-3.6.3.amd64
を指定。現在のPython3のWinPython Command PromptではPYTHONHOMEの設定がなされなくなっているこれがないと,ファイルを実行したときに
Fatal Python error: Py_Initialize: unable to load the file system codec ModuleNotFoundError: No module named 'encodings' Current thread 0x00003a98 (most recent call first):
というメッセージが表示されてしまう。
それからピルドしたファイルを実行する。
(WinPython Command PromptはPathを適切に設定して起動するコマンドプロンプトなだけで,普通のコマンドプロンプト(CMD)でもset Path=...を適切に設定していれば可)