【问题标题】:Marshalling C-style array of LPWSTR to managed string[] using pInvoke使用 pInvoke 将 LPWSTR 的 C 样式数组编组为托管字符串 []
【发布时间】:2015-05-03 21:14:13
【问题描述】:

我想调用一个分配内存的非托管方法,创建一个LPWSTRs 数组,并将其返回给托管代码。我想尽可能避免输入/输出参数并编写代码来管理内存和变量范围,所以我决定依赖使用CoTaskMemAlloc 并让编组器自动清理我。

这是我所拥有的(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);

如您所见,我尝试使用其他属性,但编组器似乎不喜欢它——我不断收到“无法编组'返回值':无效的托管/非托管类型组合。”我正在尝试将输入保持为LPWSTRs 的数组,并希望避免SAFEARRAY,其编组已被标记为过时。

【问题讨论】:

  • SizeParamIndex 不适用于返回值。你需要 void Test(out int count, [MarshalAs...] out string[] array)。还是一个安全的数组,也不过时。
  • @HansPassant 您认为从 C++ 方法中获取未知大小的字符串数组的“最省力”方法是什么?如果我可以在 C++ 中的托管堆上分配内存并返回一个 char ** 并且生成的 string[] 会自动被 GC 处理,那就太好了。
  • 这当然是不可能的。如果您不知道大小,那么您就不知道何时停止阅读元素。
  • @HansPassant 明白了。我会尝试你的第一个建议,看看它是否适合我。顺便说一句,安全数组本身并没有过时,但如果我使用MarshalAsAttribute 并指定安全数组,它会告诉我未来版本可能不支持编组安全数组。
  • @HansPassant 我可以用(out int count, [MarshalAs...][In][Out] ref string[] array) 做到这一点,但我无法让它与任何使用out string[] 的组合一起工作。这可能吗?

标签: c# c++ arrays pinvoke


【解决方案1】:

稍微修改了代码,但签名才是最重要的。该方法将一个字符串值(第三个参数)赋给传入的未初始化的 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    相关资源
    最近更新 更多