使用 pInvoke 将 LPWSTR 的 C 样式数组编组为托管字符串 []
Marshalling C-style array of LPWSTR to managed string[] using pInvoke
我想调用一个非托管方法来分配内存,创建一个 LPWSTR
数组,然后 returns 将其转为托管代码。我想尽可能避免使用 in/out 参数并编写代码来管理内存和变量范围,因此我决定依赖使用 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);
如您所见,我已尝试使用其他属性,但编组器似乎并不喜欢它——我不断收到 "Cannot marshal 'return value': Invalid managed/unmanaged type combination." 我正在尝试将键入内容保持为 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;
}
我想调用一个非托管方法来分配内存,创建一个 LPWSTR
数组,然后 returns 将其转为托管代码。我想尽可能避免使用 in/out 参数并编写代码来管理内存和变量范围,因此我决定依赖使用 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);
如您所见,我已尝试使用其他属性,但编组器似乎并不喜欢它——我不断收到 "Cannot marshal 'return value': Invalid managed/unmanaged type combination." 我正在尝试将键入内容保持为 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;
}