2017-01-12 5 views
0

Привет, я обертываю библиотеку C++ с помощью C#. Следующая функция в C++:Функция PInvoke с указателем на параметр указателя

SCREENCAPTUREDLL_API wchar_t** getAudioDeviceList(int* listSize) { 
     static std::vector<wchar_t*> descriptionList; 
     AudioCaptureList::getInstance().Update(); 
     AudioCaptureList::getInstance().getList(&descriptionList); 

     *listSize = descriptionList.size(); 
     return &descriptionList[0]; 
    } 

Обертывания с следующими C# код:

[DllImport(screenCaptureDLLPath, CallingConvention = callConversion)] 
    private static extern IntPtr getAudioDeviceList(ref int arrayCount); 

    public static string[] GetAudioDeviceList() 
    { 
     IntPtr outputStr; 
     int length = 0; 

     outputStr = getAudioDeviceList(ref length); 
     string[] resultArray = new string[length]; 
     for (int j = 0; j < length; j++) 
     { 
      resultArray[j] = Marshal.PtrToStringUni(Marshal.ReadIntPtr(outputStr, 4 * j)); 
     } 

     return resultArray; 
    } 

Это отлично работает, точно так, как я ожидал, но я собирался изменить способ, которым я возвращающийся значение из функции себя переменным по ссылке, поэтому я меняю код:

C++

SCREENCAPTUREDLL_API void getAudioDeviceList(wchar_t** list, int* listSize) { 
     static std::vector<wchar_t*> descriptionList; 
     AudioCaptureList::getInstance().Update(); 
     AudioCaptureList::getInstance().getList(&descriptionList); 

     *listSize = descriptionList.size(); 
     list = &descriptionList[0]; 
    } 

C#

[DllImport(screenCaptureDLLPath, CallingConvention = callConversion)] 
    private static extern void getAudioDeviceList(out IntPtr listRef, ref int arrayCount); 

    public static string[] GetAudioDeviceList() 
    { 
     IntPtr outputStr; 
     int length = 0; 

     getAudioDeviceList(out outputStr, ref length); 
     string[] resultArray = new string[length]; 
     for (int j = 0; j < length; j++) 
     { 
      resultArray[j] = Marshal.PtrToStringUni(Marshal.ReadIntPtr(outputStr, 4 * j)); 
     } 

     return resultArray; 
    } 

Но я получил ошибку, возвращенный адрес памяти равен нулю. В чем проблема? Пожалуйста, помогите мне понять, в чем причина проблемы и как ее исправить, спасибо!

ответ

1

Почему не работает Pinvoke? Потому что вы пытаетесь интерпретировать указатель на строку как указатель на набор строк. Но нет ничего плохого в PInvoke - это происходит потому, что на самом деле существует проблема с новой сигнатурой функции и ее внутренним кодом.

См:

SCREENCAPTUREDLL_API void getAudioDeviceList(wchar_t** listRef, int* listSize); 

не может обеспечить те же данные, как

DLL_API wchar_t** getAudioDeviceList(int* listSize) 

Поскольку первоначальное определение в основном возвращается указатель на набор указателей на строки (строк в стиле C, я имею в виду), в то время как wchar_t** listRefcan only позволяют возвращать один указатель на строку.

SCREENCAPTUREDLL_API void getAudioDeviceList(wchar_t** listRef, int* listSize) 
{ 
    ... 
    *listRef = "string"; 

Я не знаю, что происходит внутри новой версии функции (вы не показать код), но listRef = &descriptionList[0]; будет компилировать хотя won't do anything, и даже если каким-то образом *listRef = &descriptionList[0]; компилироваться не будет содержать то, что вы хотите.

Таким образом, сигнатура функции должна содержать тройной указатель, позволяющий возвращать набор строк.

SCREENCAPTUREDLL_API void getAudioDeviceList(wchar_t*** listRef, int* listSize) 
{ 
    ... 
    *listRef = &descriptionList[0]; 
} 

Тогда ваш PInvoke будет работать правильно, потому что это будет иметь тот же указатель на набор строковых указателей.

+0

Право, я попробовал listRef = & descriptionList [0]; – Liastre

+0

@ Liastre Если этот ответ помог вам решить проблему, вы можете [отметить это как принято] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work). –

+0

Удивительно, что работает, спасибо! – Liastre

Смежные вопросы