从python

时间:2018-05-06 06:40:44

标签: python c++ dll

我遇到一个问题,这个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,我和她改变了相同的环境,使用相同的代码,仍然返回相同的错误

python vs java

虽然我知道它应该是环境原因,但我真的想知道究竟是什么造成的呢?

每次运行句柄是不规则号码,我的同学的电脑获得常规号码

如:288584672,199521248,1777824736,-607161376(我不设置改造型)

this is using python call dll,cann't connect port 4000

的java

也可以获得没有负数的常规号码

如:9462886128,9454193200,9458325520,9451683632

this's java call dll

所以我认为应该是这个代码casue错误,但在其他电脑没有问题,它很棒

handle = lib.Initialization(5, '127.0.0.1'.encode(), 4000)

c ++ dll:

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;
}

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的代码