2014-01-28 194 views
1

我已成功返回的指针从C++ DLL结构(包含wchar_t*)成Python这样的: C++代码:上指针的矢量返回指针从C++ DLL到Python

... 
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代码:

#我认为,第一,第二行是不正确的(是正确的方法,使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 

值最后一排是无效的 - 这是一些内存随机配件我猜。 这是错误,我得到:

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

回答

1

一个vector是C兼容,但需要传递的C调用者(或ctypes的)的第一个元素的地址。也就是说,你必须坚持指向vector的指针,以便将其释放。我想你会从一开始就使用数组更好。您可以将参数int的参数传递给接收数组的长度。由于您正在使用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阵列。这是微软的TCHAR类型,编译为ANSI与Uni​​code。使用L"wide character string literals"

+0

非常感谢你的代码示例,它完美的工作。你能向我解释为什么'p [i] [0]'中有'[0]'? – Aleksandar

+1

'p [i]'是一个指针。您可以选择使用'p [i] .contents'或获得第0个元素。就像我说的,我宁愿使用一系列结构。在这种情况下'p [i]'是一个'myStruct'实例。但我必须重写代码才能这样做。我想我会更接近你已有的东西。 – eryksun

+0

你能否告诉我如何以及在什么时候释放记忆。我必须这样做,因为'result = new myStruct * [n];',对吧? – Aleksandar