简体   繁体   English

从C ++ dll到Python的指针矢量返回指针

[英]Returning pointer on vector of pointers from C++ dll to Python

I have successfully returned pointer to struct(that contains wchar_t* ) from c++ dll into Python like this: C++ code: 我已成功将指向指针的指针(包含wchar_t* )从c ++ dll返回到Python,如下所示:C ++代码:

...
typedef struct myStruct{
    wchar_t* id; 
    wchar_t* content; 
    wchar_t* message;
} myStruct;

DLLAPI myStruct* DLLApiGetStruct(){
    myStruct* testStruct = new myStruct();
    testStruct->id = _T("some id"); 
    testStruct->content = _T("some content"); 
    testStruct->message = _T("some message");
    return testStruct;
}

Python code: Python代码:

class MyPyStruct(Structure):
    _fields_ = [
        ("id", c_wchar_p),
        ("content", c_wchar_p),
        ("message", c_wchar_p)
        ]
...
...
myDLL = cdll.LoadLibrary('myDLL.dll')
myDLL.DLLApiGetStruct.restype = POINTER(MyPyStruct)
result = myDLL.DLLApiGetStruct().contents
print result.id, result.content, result. message# those are valid values

Ok, that works fine, the PROBLEM is that now I need to return pointer on vector of pointers to those structures. 好的,这很好, 问题是现在我需要在指向这些结构的指针的向量上返回指针。 I've tried this: 我已经试过了:

C++ code: C ++代码:

typedef std::vector<myStruct*> myVector;
...
DLLAPI myVector* DLLApiGetVector(){
    myVector* testVektor = new myVector();
    for(i=0; i< 5; i++){
        myStruct* testStruct = new myStruct();
        testStruct->id = _T("some id"); 
        testStruct->content = _T("some content"); 
        testStruct->message = _T("some message");
        testVektor->push_back(testStruct);
    }
    return testVektor;// all values in it are valid
}

Python code: Python代码:

#I think that first and second lines are incorrect (is that proper way to make restype??): #我认为第一行和第二行不正确(这是进行restype的正确方法吗?):

vectorOfPointersType = (POINTER(DeltaDataStruct) * 5)  #5 is number of structures in vector
myDLL.DLLApiGetVector.restype = POINTER(vectorOfPointersType)
vectorOfPointersOnMyStruct= myDLL.DLLApiGetVector.contents
for pointerOnMyStruct in vectorOfPointersOnMyStruct:
   result = pointerOnMyStruct.contents
   print result.id, result.content, result.message

Values in last row are NOT valid - it's some random parts of memory I guess. 最后一行中的值无效-我猜这是内存中的一些随机部分。 This is error I get: 这是我得到的错误:

UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-11: character maps to <undefined>

A vector is C compatible, but you need to pass the C caller (or ctypes) the address of the first element. vector与C兼容,但是您需要将第一个元素的地址传递给C调用者(或ctypes)。 That said, you'd have to hold on to the pointer to the vector to free it later. 就是说,您必须保持指向vector的指针,以便稍后释放它。 I think you'll be better off using an array from the start. 我认为从一开始就使用数组会更好。 You can pass the function an int out parameter to receive the length of the array. 您可以将int out参数传递给函数,以接收数组的长度。 Since you're using new to allocate, remember to catch a bad_alloc exception should the allocation fail. 由于您使用new进行分配,因此请记住,如果分配失败,则会捕获bad_alloc异常。

Personally, I'd use an array of structs instead an array of pointers, such that the data is in single contiguous block. 就个人而言,我将使用结构数组而不是指针数组,以使数据位于单个连续的块中。 This yields a cleaner interface in ctypes. 这会在ctypes中产生更清晰的界面。 With an array of pointers you have to dereference twice to get at the struct. 使用指针数组,您必须取消引用两次才能获取该结构。

C++: C ++:

#include <new>
#include <cwchar>

typedef struct myStruct {
    wchar_t *id;
    wchar_t *content;
    wchar_t *message;
} myStruct;

const wchar_t ID[] = L"some id";
const wchar_t CONTENT[] = L"some content";
const wchar_t MESSAGE[] = L"some message";

DLLAPI myStruct **DLLApiGetArray(int *size)
{
    int i, n = 5;
    myStruct **result;
    try {
        result = new myStruct *[n];
        for(i = 0; i < n; i++) {
            myStruct *tmp = new myStruct();
            tmp->id = new wchar_t[wcslen(ID) + 1];
            tmp->content = new wchar_t[wcslen(CONTENT) + 1];
            tmp->message = new wchar_t[wcslen(MESSAGE) + 1];
            wcscpy(tmp->id, ID);
            wcscpy(tmp->content, CONTENT);
            wcscpy(tmp->message, MESSAGE);
            result[i] = tmp;
        }
    } catch (std::bad_alloc &ba) {
        *size = -1; return NULL;
    }
    *size = n; return result;
}

Python: 蟒蛇:

from ctypes import *

class myStruct(Structure):
    _fields_ = [
        ("id", c_wchar_p),
        ("content", c_wchar_p),
        ("message", c_wchar_p)
    ]

myDLL = cdll.myDLL
myDLL.DLLApiGetArray.restype = POINTER(POINTER(myStruct))
myDLL.DLLApiGetArray.argtypes = [POINTER(c_int)]

n = c_int()
p = myDLL.DLLApiGetArray(byref(n))
n = n.value

Example looping through the result: 遍历结果的示例:

>>> for i in range(n):
...     print i, p[i][0].id
...
0 some id
1 some id
2 some id
3 some id
4 some id

FYI, it's incorrect to use the _T macro with explicit wchar_t arrays. 仅供参考,将_T宏与显式wchar_t数组一起使用是不正确的。 That's for Microsoft's TCHAR type, for compiling as ANSI vs Unicode. 这适用于Microsoft的TCHAR类型,可编译为ANSI vs Unicode。 Use L"wide character string literals" . 使用L"wide character string literals"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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