如何通过 p/invoke 将 c# 字符串传递给 linux/glibc wchar_t * 参数?
How to pass c# strings through p/invoke to linux/glibc wchar_t * parameters?
我有一个 .NET Core 2.2 C# 应用程序,它使用 DllImport 在 CentOS 7.5 上引入本机共享库(使用 gcc 编译的 C++ extern "C" 接口)。 C++ 库中的函数需要 wchar_t * 参数,但这些参数似乎被编组为 UTF16 字符串,而不是 gcc/glibc 中实现的 UTF32 字符串。这是(我的)程序员错误还是应该向 .NET Core 团队提出?
这是我尝试调用的高度复杂的方法:
void wchar_tTest(const wchar_t *arg1, const wchar_t *arg2)
{
std::wcout << L"wchar_tTest: arg1: " << arg1 << L", arg2: " << arg2 << std::endl;
char *s = (char *)arg1;
for (int i = 0; i < 12; i++)
{
printf("%d: %c\n", i, s[i]);
}
}
我尝试在托管端的 DllImport 上使用 MarshalAs(UnmanagedType.LPWSTR)
and/or CharSet.Unicode
无济于事。这些都产生相似的结果:
[DllImport("cover", EntryPoint = "wchar_tTest", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void LPWSTRStringTest([MarshalAs(UnmanagedType.LPWStr)] string arg1, [MarshalAs(UnmanagedType.LPWStr)] string arg2);
[DllImport("cover", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void wchar_tTest(string arg1, string arg2);
调用看起来像这样(stringTest()
是一个类似的调用,但调用的是带有 char *
个参数的函数):
string arg1 = "Hello!";
string arg2 = "Goodbye!";
stringTest(arg1, arg2);
wchar_tTest(arg1, arg2);
LPWSTRStringTest(arg1, arg2);
当通过wcout
转储参数时,Hello!
变为Hlo
,Goodbye!
变为Gobe
。当您逐个字符查看时,输出看起来很像 UTF16……看起来 wchar_t *
跳过所有其他 UTF16 字符(我假设将其视为 UTF32 字符串)。
wchar_tTest: arg1: Hlo, arg2: Gobe
0: H
1:
2: e
3:
4: l
5:
6: l
7:
8: o
9:
10: !
11:
有没有办法在不进行自定义编组的情况下解决这个问题?毕竟我已经阅读过了,这似乎应该是一个简单的任务,但我在这里。
文本按预期和设计编组为 UTF16。您需要:
- 调整您的 C++ 代码以在 UTF16 上运行,或者
- 使用其他编码的自定义编组,例如UTF8 或 UTF32。
鉴于我看到的流量量没有很好的答案,我将 post 我正在使用的短期黑客来解决这个问题,因为世界的 C++/本地库方面不能改变了...
我修改了 DllImport 以声明 byte[] 参数
[DllImport("cover", EntryPoint = "wchar_tTest", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void utf32Test(byte[] arg1, byte[] arg2);
并创建了 .NET 字符串的 UTF32 编码版本
string arg1 = "Hello!";
byte[] arg1UTF32 = Encoding.UTF32.GetBytes(arg1);
string arg2 = "Goodbye!";
byte[] arg2UTF32 = Encoding.UTF32.GetBytes(arg2);
utf32Test(arg1UTF32, arg2UTF32);
瞧,你得到了预期的输出字符串和数组内容
wchar_tTest: arg1: Hello!, arg2: Goodbye!
0: H
1:
2:
3:
4: e
5:
6:
7:
8: l
9:
10:
11:
虽然这不是很便携,但当您在 Windows 系统上 运行 时当然会失败。我希望有更好的答案。
我有一个 .NET Core 2.2 C# 应用程序,它使用 DllImport 在 CentOS 7.5 上引入本机共享库(使用 gcc 编译的 C++ extern "C" 接口)。 C++ 库中的函数需要 wchar_t * 参数,但这些参数似乎被编组为 UTF16 字符串,而不是 gcc/glibc 中实现的 UTF32 字符串。这是(我的)程序员错误还是应该向 .NET Core 团队提出?
这是我尝试调用的高度复杂的方法:
void wchar_tTest(const wchar_t *arg1, const wchar_t *arg2)
{
std::wcout << L"wchar_tTest: arg1: " << arg1 << L", arg2: " << arg2 << std::endl;
char *s = (char *)arg1;
for (int i = 0; i < 12; i++)
{
printf("%d: %c\n", i, s[i]);
}
}
我尝试在托管端的 DllImport 上使用 MarshalAs(UnmanagedType.LPWSTR)
and/or CharSet.Unicode
无济于事。这些都产生相似的结果:
[DllImport("cover", EntryPoint = "wchar_tTest", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void LPWSTRStringTest([MarshalAs(UnmanagedType.LPWStr)] string arg1, [MarshalAs(UnmanagedType.LPWStr)] string arg2);
[DllImport("cover", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void wchar_tTest(string arg1, string arg2);
调用看起来像这样(stringTest()
是一个类似的调用,但调用的是带有 char *
个参数的函数):
string arg1 = "Hello!";
string arg2 = "Goodbye!";
stringTest(arg1, arg2);
wchar_tTest(arg1, arg2);
LPWSTRStringTest(arg1, arg2);
当通过wcout
转储参数时,Hello!
变为Hlo
,Goodbye!
变为Gobe
。当您逐个字符查看时,输出看起来很像 UTF16……看起来 wchar_t *
跳过所有其他 UTF16 字符(我假设将其视为 UTF32 字符串)。
wchar_tTest: arg1: Hlo, arg2: Gobe
0: H
1:
2: e
3:
4: l
5:
6: l
7:
8: o
9:
10: !
11:
有没有办法在不进行自定义编组的情况下解决这个问题?毕竟我已经阅读过了,这似乎应该是一个简单的任务,但我在这里。
文本按预期和设计编组为 UTF16。您需要:
- 调整您的 C++ 代码以在 UTF16 上运行,或者
- 使用其他编码的自定义编组,例如UTF8 或 UTF32。
鉴于我看到的流量量没有很好的答案,我将 post 我正在使用的短期黑客来解决这个问题,因为世界的 C++/本地库方面不能改变了...
我修改了 DllImport 以声明 byte[] 参数
[DllImport("cover", EntryPoint = "wchar_tTest", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void utf32Test(byte[] arg1, byte[] arg2);
并创建了 .NET 字符串的 UTF32 编码版本
string arg1 = "Hello!";
byte[] arg1UTF32 = Encoding.UTF32.GetBytes(arg1);
string arg2 = "Goodbye!";
byte[] arg2UTF32 = Encoding.UTF32.GetBytes(arg2);
utf32Test(arg1UTF32, arg2UTF32);
瞧,你得到了预期的输出字符串和数组内容
wchar_tTest: arg1: Hello!, arg2: Goodbye!
0: H
1:
2:
3:
4: e
5:
6:
7:
8: l
9:
10:
11:
虽然这不是很便携,但当您在 Windows 系统上 运行 时当然会失败。我希望有更好的答案。