我遇到一个问题,这个dll java或php可以调用成功,但是当我使用python调用获取访问冲突错误时,
我想知道c ++ char *是ctypes c_char_p的错误,我该如何使用python ctypes map c ++ char *
c ++ dll define
#define Health_API extern "C" __declspec(dllexport)
Health_API unsigned long Initialization(int m_type,char * m_ip,int m_port)
Health_API int GetRecordCount(unsigned long m_handle)
python代码
from ctypes import *
lib = cdll.LoadLibrary(r"./Health.dll")
inita = lib.Initialization
inita.argtype = (c_int, c_char_p, c_int)
inita.restype = c_ulong
getcount = lib.GetRecordCount
getcount.argtype = c_ulong
getcount.retype = c_int
# here call
handle = inita(5, '127.0.0.1'.encode(), 4000)
print(handle)
result = getcount(handle)
错误信息:
2675930080
Traceback (most recent call last):
File "C:/Users/JayTam/PycharmProjects/DecoratorDemo/demo.py", line 14, in <module>
print(getcount(handle))
OSError: exception: access violation reading 0x000000009F7F73E0
我发现如果没有定义restype = long,它会返回负数,这是一个值得注意的问题,但是我改变了restype = u_int64,它也不能连接。
令我高兴的是,我的shcoolmate使用她的电脑(win7 x64)调用相同的dll成功,使用简单的代码如下
from ctypes import *
lib = cdll.LoadLibrary("./Health.dll")
handle = lib.Initialization(5, '127.0.0.1'.encode(), 4000)
lib.GetRecordList(handle, '')
我是win10 x64,我的python环境是annaconda,我和她改变了相同的环境,使用相同的代码,仍然返回相同的错误
虽然我知道它应该是环境原因,但我真的想知道究竟是什么造成的呢?
每次运行句柄是不规则号码,我的同学的电脑获得常规号码
如:288584672,199521248,1777824736,-607161376(我不设置改造型)
this is using python call dll,cann't connect port 4000
也可以获得没有负数的常规号码
如:9462886128,9454193200,9458325520,9451683632
所以我认为应该是这个代码casue错误,但在其他电脑没有问题,它很棒
handle = lib.Initialization(5, '127.0.0.1'.encode(), 4000)
Health_API unsigned long Initialization(int m_type,char* m_ip,int m_port)
{
CHandleNode* node;
switch(m_type)
{
case BASEINFO:
{
CBaseInfo* baseInfo = new CBaseInfo;
baseInfo->InitModule(m_ip,m_port);
node = m_info.AddMCUNode((unsigned long)baseInfo);
node->SetType(m_type);
return (unsigned long)baseInfo;
}
break;
case BASEINFO_ALLERGENS:
{
CBaseInfo_Allergens* baseInfo_Allergens = new CBaseInfo_Allergens;
baseInfo_Allergens->InitModule(m_ip,m_port);
node = m_info.AddMCUNode((unsigned long)baseInfo_Allergens);
node->SetType(m_type);
return (unsigned long)baseInfo_Allergens;
}
break;
. (case too many, ... represent them)
.
.
}
return -1;
}
Health_API int GetRecordList(unsigned long m_handle,char* m_index)
{
CHandleNode* node = m_info.GetMCUNode(m_handle);
if( node == NULL)
{
return -1;
}
switch(node->GetType())
{
case BASEINFO:
{
CBaseInfo* baseInfo = (CBaseInfo*)m_handle;
return baseInfo->GetRecordList(m_index);
}
break;
case BASEINFO_ALLERGENS:
{
CBaseInfo_Allergens* baseInfo_Allergens = (CBaseInfo_Allergens *)m_handle;
return baseInfo_Allergens->GetRecordList(m_index);
}
break;
. (case too many, ... represent them)
.
.
}
return -1;
}
答案 0 :(得分:2)
获得C ++的源代码可能会有所帮助,但我可以采取一些猜测
我不认为这是相关的,但是:
getcount.retype
缺少s
,应该是restype
。 argtype
定义为数组而不是元组,如果只有一个参数,我仍然使用一个元素的数组。 如果char*
是以空字符结尾的字符串,则确实需要使用c_char_p
。在这种情况下,强烈建议在const
参数中添加m_ip
。
如果char*
是指向原始缓冲区的指针(由调用函数填充或不填充)(这不是这种情况),则需要使用POINTER(c_char)
而不是c_char_p
根据错误消息,您的handle
是一个指针,您应该在C ++代码中使用正确的类型:void*
。在你的python中你应该使用c_void_p
是64位代码吗?使用什么工具链/编译器来构建DLL?这个工具链中unsigned long的大小是多少?
修改:问题的原因:Is Python's ctypes.c_long 64 bit on 64 bit systems?
handle
是DLL中的指针,当然使用编译器构建,其中long
为64位,但对于Windows上的python 64位,long
为32位,它无法存储您的指针。你真的应该使用void*
首先,您可以尝试在python中使用c_void_p
来处理句柄,而无需修改源代码,它可能会根据所使用的编译器而有效。但由于long
类型的大小未由任何标准定义,并且可能无法存储指针,因此您应该在C ++代码中使用void*
或uintptr_t
Edit2:如果你使用的是visual studio,而不是GCC,那么long的大小只有32位(Size of long vs int on x64 platform) 所以你必须修复DLL的代码