使用pInvoke将C样式的LPWSTR数组编组到托管字符串[]

时间:2015-05-03 21:14:14

标签: c# c++ arrays pinvoke

我想调用一个非托管方法来分配内存,创建一个LPWSTR数组,并将其返回给托管代码。我想避免输入/输出参数和编写代码来尽可能地管理内存和变量范围,所以我决定依赖于使用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);

正如你所看到的,我已经尝试使用其他属性但是marshaller似乎并不喜欢它 - 我一直得到“无法编组'返回值':无效的托管/非托管类型组合。”我正在尝试将键入作为LPWSTR的数组进行维护,并希望避免使用SAFEARRAY,因为编组已被标记为过时。

1 个答案:

答案 0 :(得分:0)

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

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