3

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;
}
JayTam
  • 209
  • 2
  • 11
  • Java is returning 64 bits values (notice how big the return number is). In python if you do not specify the restype, the default is an `int`, which is an signed integer, that why you do see negative number. In python you must use use `c_void_p`, and as I already explained, you also should fix the code of the DLL – benjarobin May 07 '18 at 16:46
  • In Python ctypes `u_int64` type does not exist as I know of. As I already explained, you should use `c_void_p` even if the C function prototype is an integer – benjarobin May 07 '18 at 16:48
  • The code of your shcoolmate is wrong, she is just lucky that the pointer fit in a 32 bits integer – benjarobin May 07 '18 at 16:50
  • think you, I will modify it soon – JayTam May 07 '18 at 17:34

1 Answers1

2

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

benjarobin
  • 4,410
  • 27
  • 21
  • thanks,do you think is the difference in win7 and win10 ? I cann't think about more differences – JayTam May 07 '18 at 15:54
  • Nop, the problem is not there. First your C++ code is wrong and must be fixed as already explained: A pointer should never be put in an unsigned long integer, depending of the compiler and of the platform, it may not fit in the integer. Please explain how the DLL was built, with which toolchain/compiler and in which version. – benjarobin May 07 '18 at 16:39
  • the DLL use vs 2010 build ,x64 , release,I will fix the code of DLL tomorrow,it’s 1:40 ,I hava to go to sleep. – JayTam May 07 '18 at 17:42
  • You should read again my messages, I didn't know that you were using visual studio. The problem is also in your DLL source code since with visual studio a long cannot store a pointer on 64bits build – benjarobin May 08 '18 at 10:17
  • thank you , I will tell c++ code wirter,I dont understand c++ – JayTam May 08 '18 at 11:14
  • But I still have a problem that we use java/php/c++ call the same dll file many times,hava no problem – JayTam May 08 '18 at 11:16
  • There is something that I still not understand... The DLL is a 32 bits or a 64bits DLL ? Is it PHP, python and Java 64 bits or 32 bits ? Could you give 4 values of handle from the wrapper in Java, python and PHP and also indicate if the code is working or crashing for each case – benjarobin May 08 '18 at 12:19
  • all of them is 64 bits, include DLL, programming language and operating system.windows x64 usigned long in Visual c++ is 4 bytes(32bit),but java get a handle value is 9455606144 more than 2^32-1,Why ? in python handle value more than 2^32-1,handle is negative number – JayTam May 08 '18 at 14:17
  • oh yeah ,I change unsigned long to unsigned long long it success run,the handle is 2432317092832 ,length is 13,over flow unsigned long size. thank you ,thank you thank you,say three times the important thing – JayTam May 09 '18 at 07:09