【发布时间】: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[]的组合一起工作。这可能吗?