2014-01-28 151 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