我已成功将指向struct(包含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代码:
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
好的,工作正常,问题是现在我需要在指向这些结构的指针向量上返回指针。我试过这个:
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代码:
#我认为第一行和第二行是不正确的(这是正确的重做方式吗?):
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
最后一行的值无效 - 我猜它是内存的一些随机部分。 这是我得到的错误:
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-11: character maps to <undefined>
答案 0 :(得分:1)
vector
与C兼容,但您需要传递C调用者(或ctypes)第一个元素的地址。也就是说,你必须坚持指向vector
的指针才能在以后释放它。我想你最好从一开始就使用数组。您可以将函数传递int
out参数以接收数组的长度。由于您使用new
进行分配,因此如果分配失败,请记住捕获bad_alloc
异常。
就个人而言,我会使用一个结构数组而不是一个指针数组,这样数据就在单个连续的块中。这样可以在ctypes中生成更清晰的界面。使用指针数组,您必须取消引用两次以获取结构。
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
循环结果的示例:
>>> 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
仅供参考,将_T
宏与显式wchar_t
数组一起使用是不正确的。这是Microsoft的TCHAR
类型,用于编译为ANSI vs Unicode。使用L"wide character string literals"
。