使用PINVOKE编组LPWSTR的C风格数组,以托管字符串[]

Marshalling C-style array of LPWSTR to managed string[] using pInvoke

本文关键字:字符串 数组 编组 PINVOKE LPWSTR 风格 使用      更新时间:2023-10-16

我想调用一种不受管理的方法,该方法分配内存,创建LPWSTR s的数组,然后将其返回到托管代码。我想避免使用/输出参数和编写代码以尽可能多地管理内存和可变范围,因此我决定依靠使用CoTaskMemAlloc并让Marshaller自动清理我。

这是我拥有的(MSDN上的P/Invoke教程方法的修改版):

extern "C" DLL1_API LPWSTR *TestArrayOfStrings(_In_ int count)
{
    STRSAFE_LPWSTR temp = NULL;
    wchar_t * ppStrArray[10] = { NULL };
    const size_t alloc_size = sizeof(wchar_t *) * 10;
    for (int i = 0; i < 10; i++)
    {
        temp = (STRSAFE_LPWSTR)CoTaskMemAlloc(alloc_size);
        if (i % 2 == 0)
            StringCchCopy(temp, alloc_size, L"0123456789");
        else
            StringCchCopy(temp, alloc_size, L"9876543210");
        CoTaskMemFree(ppStrArray[i]);
        ppStrArray[i] = temp;
    }
    count = 10;
    return ppStrArray;
}

在托管方面:

[DllImport("Dll1.Windows.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, ArraySubType = UnmanagedType.LPWStr)]
public static extern string[] TestArrayOfStrings(out int count);

您可以看到,我尝试使用其他属性,但守卫似乎并不喜欢它 - 我一直在获得"无法元帅的'返回值':无效的托管/无管理类型组合"。我试图将键入作为LPWSTR s的数组,并希望避免使用SAFEARRAY,为其编组被标记为已过时。

稍微修改的代码,但签名很重要。此方法将字符串值(第三个参数)分配给传递的非初始化out数组的第一个元素。

[DllImport("Dll1.Windows.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    public static extern void TestArrayOfStrings(
        [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] [Out] out string[] test, 
        out int size, string someString);
extern "C" DLL1_API void TestArrayOfStrings(wchar_t ***strings, int *size, wchar_t *someString){
    const size_t alloc_size = 64; 
    STRSAFE_LPWSTR temp = (STRSAFE_LPWSTR)CoTaskMemAlloc(alloc_size);
    StringCchCopy(temp, alloc_size, someString);
    *strings = (wchar_t **)CoTaskMemAlloc(sizeof(wchar_t));
    *strings[0] = temp;
    *size = 1;
}