我遇到访问冲突。我正在使用带有单个函数的 C++ dll,该函数尝试从 PyObject 中提取字符串。看来 PyObject *args 参数的类型不正确。这是来自其他地方发布的类似示例。传递 c_char_p (传递给采用 c_char_p 的函数)并返回 PyObject * 效果很好。
加载 C++ dll 并使用对象调用函数。设置正确的路径。
使用 msvc 2022 和 Python 3.9。
Python(使用 PYFUNCTYPE 或 CFUNCTYPE 没有区别):
import ctypes
import sys
import os
y = __file__
str_path = os.path.dirname(os.path.realpath("..\\..\\string\\x64\\Debug\\string.dll"))
handle = ctypes.CDLL(str_path + "/string.dll")
handle.My_Function3.argtypes = [ctypes.py_object]
handle.My_Function3.restype = ctypes.py_object
z = handle.My_Function3(y)
print(z)
创建添加单个函数的 C++ string.dll。我已验证地址是否正确传递,但随后我在函数中收到内部错误。
添加到 string.dll 的 C++ 文件(添加到 Windows dll)dllmain.cop 未更改:
函数.cpp:
#include "pch.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
char s[100];
static PyObject *MyError;
extern "C"
{
__declspec(dllexport) PyObject* __stdcall My_Function3(PyObject *args)
{
const char* str;
char s[100];
// Code fails here with access violation
if (!PyArg_ParseTuple(args, "s", &str))
return NULL;
if (strlen(str) > 100)
{
PyErr_SetString(MyError, "Error: string too long");
return NULL;
}
strcat_s(s, 100, str);
return Py_BuildValue("s", s);
}
}
稍微修改一下代码,发现错误是在异常处理中。 (此后,我将此示例用作扩展,并对字符串副本进行了必要的更改。)
使用
PyDLL
进行正确的 GIL 处理,使用 __cdecl
保证正确性(是的,__stdcall
可以在 64 位上运行,但会破坏可移植性)。 py_object
会起作用的。这是一个调用 PyArg_ParseTuple
本身的示例:
import ctypes as ct
dll = ct.PyDLL('python3')
dll.PyArg_ParseTuple.argtypes = ct.py_object, ct.c_char_p
dll.PyArg_ParseTuple.restype = ct.c_int
a1 = ct.c_char_p()
a2 = ct.c_int()
print('result:', dll.PyArg_ParseTuple(('abc一二三', 123), b'si', ct.byref(a1), ct.byref(a2)))
print(a1.value, a1.value.decode(), a2.value)
输出:
result: 1
b'abc\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89' abc一二三 123