简体   繁体   中英

call c++ function from python

I meet a question,this dll java or php can call successful,but when I use python call get access violation error,

I want to know is c++ char* is error to ctypes c_char_p, how can I use 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 code

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)

error info:

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

After modification

I find if not define restype=long , it will return negative number,this is a noteworthy problem,but I change the restype=u_int64,it cann't connect as well.

It is delightful that my shcoolmate use her computer(win7 x64) call the same dll success,use simple code as follow

from ctypes import *

lib = cdll.LoadLibrary("./Health.dll")
handle = lib.Initialization(5, '127.0.0.1'.encode(), 4000)
lib.GetRecordList(handle, '')

I am win10 x64,my python environment is annaconda,and I change the same environment as her,use the same code,still return the same error

python vs java

Although I konw it shuould be the environment cause,I really want to konw What exactly caused it?

python

each run handle is Irregular number,my classmate's pc get regular number

such as :288584672,199521248,1777824736,-607161376(I dont set restype)

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

java

also get regular number without negative number

such as :9462886128,9454193200,9458325520,9451683632

this's java call dll

so I think should be this code casue error,but in other pc no problem,it's amazing

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

It may help to have the source code of the C++, but I can take some guesses

I don't think this is related, but:

  • getcount.retype is missing an s , it should be restype .
  • And I always define argtype as an array instead of a tuple, and if there is only one argument I still use an array of one element.

If the char* is a null terminated string, you need indeed to use c_char_p . And in this case it is highly recommended to add a const to the m_ip argument.

If the char* is a pointer to a raw buffer (filled or not by the calling function), which is not the case here, you need to use POINTER(c_char) and not c_char_p

Base on the error message, your handle is a pointer, you should use for that the right type in your C++ code: void* . And in your python you should use c_void_p

Is it 64 bits code ? What toolchain/compiler was used to build the DLL ? What is the size of unsigned long in this toolchain ?

Edit: Here the reason of your problem: Is Python's ctypes.c_long 64 bit on 64 bit systems?

handle is a pointer in your DLL, and was certainly built using a compiler where a long is 64 bits, but for python 64 bits on Windows a long is 32 bits, which cannot store your pointer. Your really should use a void*

First you could try to use c_void_p in your python for the handle without modifying your source code, it may works depending of the compiler used. But since the size of the long type is not defined by any standard, and may not be able to store a pointer, you really should use in your C++ code void* or uintptr_t

Edit2: If you are using visual studio, and not GCC, the size of a long is only 32 bits ( Size of long vs int on x64 platform ) So you must fix the code of the DLL

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM