使用带有 py_object 参数的 Python ctypes 调用 C++ 函数

问题描述 投票:0回答:1

我遇到访问冲突。我正在使用带有单个函数的 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);
    }
}

稍微修改一下代码,发现错误是在异常处理中。 (此后,我将此示例用作扩展,并对字符串副本进行了必要的更改。)

python exception ctypes
1个回答
0
投票

使用

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
© www.soinside.com 2019 - 2024. All rights reserved.