вызов функции c ++ из python - PullRequest
0 голосов
/ 06 мая 2018

Я сталкиваюсь с вопросом, может ли 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)

код питона

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, он также не может подключиться.

Восхитительно, что мой школьный товарищ использует свой компьютер (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, и я изменяю ту же среду, что и она, использую тот же код, но по-прежнему возвращаю ту же ошибку

питон против Java

Хотя я знаю, что это должна быть причина окружающей среды, я действительно хочу знать, Что именно вызвало это?

питон

каждый прогон дескриптор - это неправильный номер, компьютер моего одноклассника получает обычный номер

, например: 288584672,199521248,1777824736, -607161376 (я не устанавливаю restype)

это использует DLL-вызов Python, невозможно подключить порт 4000

Java

также получите обычный номер без отрицательного числа

, например: 9462886128,9454193200,9458325520,9451683632

это java вызов dll

так что я думаю, что это должно быть из-за ошибки в коде, но в других ПК нет проблем, это удивительно

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 голосов
/ 06 мая 2018

Может быть полезно иметь исходный код C ++, но я могу принять некоторые предположения

Не думаю, что это связано, но:

  • getcount.retype отсутствует s, должно быть restype.
  • И я всегда определяю argtype как массив вместо кортежа, и если есть только один аргумент, я все равно использую массив из одного элемента.

Если char* является строкой с нулевым символом в конце, вам действительно нужно использовать c_char_p. И в этом случае настоятельно рекомендуется добавить const к аргументу m_ip.

Если char* является указателем на необработанный буфер (заполняется или не вызывается вызывающей функцией), что здесь не так, вам нужно использовать POINTER(c_char), а не c_char_p

Основываясь на сообщении об ошибке, ваш handle является указателем, для этого вы должны использовать правильный тип в вашем коде C ++: void*. И в вашем питоне вы должны использовать c_void_p

Это 64-битный код? Какой набор инструментов / компилятор использовался для сборки DLL? Каков размер unsigned long в этом наборе инструментов?

Редактировать: Вот причина вашей проблемы: Является ли Python ctypes.c_long 64-битным в 64-битных системах?

handle - это указатель в вашей DLL, и он, безусловно, был создан с использованием компилятора, где long равен 64 битам, но для Python 64 бит в Windows long равен 32 битам, который не может хранить ваш указатель. Вы действительно должны использовать void*

Сначала вы можете попробовать использовать c_void_p в вашем python для дескриптора без изменения исходного кода, он может работать в зависимости от используемого компилятора. Но так как размер типа long не определен никаким стандартом и может не иметь возможности хранить указатель, вам действительно следует использовать в своем коде C ++ void* или uintptr_t

Edit2: если вы используете Visual Studio, а не GCC, размер long составляет всего 32 бита ( Размер long против int на платформе x64 ) Таким образом, вы должны исправить код DLL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...