带有指针到指针参数的 PInvoke 函数

PInvoke function with pointer to pointer parameter

本文关键字:指针 PInvoke 函数 参数      更新时间:2023-10-16

你好,我正在用 C# 包装C++库。C++中的下一个函数:

    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;
    }

但是我得到错误,返回的内存地址为零。这里有什么问题?请帮助我了解导致问题的原因以及如何解决,谢谢!

为什么 Pinvoke 不起作用?因为您尝试将指向字符串的指针解释为指向一组字符串的指针。但是 PInvoke 并没有错 - 发生这种情况是因为新功能签名及其内部代码实际上存在问题。

看:

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

无法提供相同的数据,例如

DLL_API wchar_t** getAudioDeviceList(int* listSize)

因为原始定义基本上返回了指向一组指向字符串的指针(我的意思是 C 样式字符串)的指针,而wchar_t** listRef只能允许返回指向字符串的单个指针。

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

我不知道新版本的函数内部发生了什么(您没有显示代码),但是listRef = &descriptionList[0];会编译,尽管不会做任何事情,即使*listRef = &descriptionList[0];以某种方式编译,它也不会包含您想要的内容。

因此,函数签名应包含三重指针,以允许返回一组字符串。

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

然后,您的 PInvoke 将正常工作,因为它将具有指向一组字符串指针的相同指针。