gpt4 book ai didi

python - 带有回调 : access violation on exit 的 ctypes

转载 作者:行者123 更新时间:2023-11-30 22:16:32 26 4
gpt4 key购买 nike

这个问题我以前也问过,没有得到回复。我又问了一遍,这次简单多了。

我有一个由Python ctypes调用的dll,带有回调函数。回调始终正确工作(如果我在 Visual Studio 中单步执行程序,我可以看到它正在运行),但退出时 Visual Studio 会引发“访问冲突”异常。但是如果我从 dll 中删除对回调的调用,它会正常退出而不会出现访问冲突。

我还必须做些什么才能通过回调退出 dll 吗?我已经研究了几个小时,但在网上没有找到任何可以解决这个问题的东西。

这是 ctypes 代码。我省略了 dll 代码以保持简短(它是用 NASM 编写的),但如果需要,我也可以发布它。

def SimpleTestFunction_asm(X):

Input_Length_Array = []
Input_Length_Array.append(len(X)*8)

CA_X = (ctypes.c_double * len(X))(*X)

length_array_out = (ctypes.c_double * len(Input_Length_Array))(*Input_Length_Array)

hDLL = ctypes.WinDLL("C:/Test_Projects/SimpleTestFunction/SimpleTestFunction.dll")
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_longlong)]
CallName.restype = ctypes.POINTER(ctypes.c_int64)
#__________
#The callback function

LibraryCB = ctypes.WINFUNCTYPE(ctypes.c_double, ctypes.c_double)

def LibraryCall(ax):
bx = math.ceil(ax)
return (bx)

lib_call = LibraryCB(LibraryCall)
lib_call = ctypes.cast(lib_call,ctypes.POINTER(ctypes.c_longlong))

#__________

ret_ptr = CallName(CA_X,length_array_out,lib_call)

我真的非常感谢任何关于如何解决这个问题的想法。我希望这篇简化的文章能有所帮助。

非常感谢。

最佳答案

我对您的代码做了一些小的更改,以使其实际运行(导入),并添加了一个打印来查看传递的对象的地址和返回值,此外还创建了一个等效的 C DLL 以确保指针正确传递和回调有效。

Python:

import ctypes
import math

def SimpleTestFunction_asm(X):
Input_Length_Array = []
Input_Length_Array.append(len(X)*8)

CA_X = (ctypes.c_double * len(X))(*X)

length_array_out = (ctypes.c_double * len(Input_Length_Array))(*Input_Length_Array)

hDLL = ctypes.WinDLL('test')
CallName = hDLL.Main_Entry_fn
CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_longlong)]
CallName.restype = ctypes.POINTER(ctypes.c_int64)

LibraryCB = ctypes.WINFUNCTYPE(ctypes.c_double, ctypes.c_double)

def LibraryCall(ax):
bx = math.ceil(ax)
return (bx)

lib_call = LibraryCB(LibraryCall)
lib_call = ctypes.cast(lib_call,ctypes.POINTER(ctypes.c_longlong))

ret_ptr = CallName(CA_X,length_array_out,lib_call)
print('{:016X} {:016X} {:016X} {}'.format(ctypes.addressof(CA_X),ctypes.addressof(length_array_out),ctypes.addressof(lib_call.contents),ret_ptr.contents))

SimpleTestFunction_asm([1.1,2.2,3.3])

Test.DLL来源:

#include <inttypes.h>
#include <stdio.h>

typedef double (*CB)(double);

__declspec(dllexport) int64_t* __stdcall Main_Entry_fn(double* p1, double* p2, long long* p3)
{
static int64_t x = 123;
double out = ((CB)p3)(1.1);
printf("%p %p %p %lf\n",p1,p2,p3,out);
return &x;
}

输出:

0000021CC99B23A8 0000021CCBADAC10 0000021CCBC90FC0 2.000000
0000021CC99B23A8 0000021CCBADAC10 0000021CCBC90FC0 c_longlong(123)

可以看到指针是相同的,并且回调返回值和函数返回值是正确的。

您的 NASM 代码可能未正确实现调用约定或损坏访问数组的堆栈。我只是做了最少的事情来让你的 Python 代码工作。我确实认为很奇怪,length_array_out 始终是一个长度为 1 的 double 组,其值是输入数组 X 长度的 8 倍。 NASM 代码如何知道数组有多长?

您可以更加类型正确并声明以下内容,而不是将回调转换为 long long *:

CALLBACK = ctypes.WINFUNCTYPE(ctypes.c_double, ctypes.c_double)

CallName.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double),CALLBACK]
CallName.restype = ctypes.POINTER(ctypes.c_int64)


@CALLBACK
def LibraryCall(ax):
bx = math.ceil(ax)
return (bx)

ret_ptr = CallName(CA_X,length_array_out,LibraryCall)

关于python - 带有回调 : access violation on exit 的 ctypes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49932140/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com