我有一个非托管c ++ DLL,我需要从 Windows Mobile C#app 调用。
我有C#包装器,它在桌面上运行良好。我可以从C#桌面程序调用DLL函数并传递字符串没有问题。
但是,当我编译lib和移动平台的包装器时,我在DllImport行中收到错误,指出CharSet.ANSI无法识别。我允许写的唯一选项是CharSet.Auto和CharSet.Unicode。
问题在于,无论此设置如何,c ++函数中接收的字符串都是宽字符串,而不是它们期望的纯字符串*。
我们可以使用wcstombs()来翻译每个c ++函数开头的所有字符串,但我宁愿不修改lib到这样的程度......
有没有办法修复与.NET Compact Framework一起使用的C#和C之间的编组?
答案 0 :(得分:7)
不,没有。
[...] .NET Compact Framework 仅支持Unicode ,因此仅包含 CharSet.Unicode(和CharSet.Auto 它等于Unicode)值 不支持任何条款 声明声明。这意味着 ExactSpelling属性也不是 支持的。
因此,如果您的DLL功能 需要一个ANSI字符串 在DLL中执行转换, 或将字符串转换为字节数组 使用重载的GetBytes方法 之前的ASCIIEncoding类 从.NET开始调用该函数 Compact Framework将始终通过 指向Unicode字符串的指针。 [...]
解决方案是:
DLL中的函数
int MARSHALMOBILEDLL_API testString(const char* value);
const char* MARSHALMOBILEDLL_API testReturnString(const char* value);
<强>包装强>
[DllImport("marshalMobileDll.dll")]
public static extern int testString(byte[] value);
[DllImport("marshalMobileDll.dll")]
public static extern System.IntPtr testReturnString(byte[] value);
致电代码
string s1 = "1234567";
int v = Wrapper.testString( Encoding.ASCII.GetBytes(s1));
string s2 = "abcdef";
IntPtr ps3 = Wrapper.testReturnString(Encoding.ASCII.GetBytes(s2));
string s3 = IntPtrToString(ps3);
private string IntPtrToString(IntPtr intPtr)
{
string retVal = "";
byte b = 0;
int i = 0;
while ((b = Marshal.ReadByte(intPtr, i++)) != 0)
{
retVal += Convert.ToChar(b);
}
return retVal;
}
答案 1 :(得分:2)
Windows CE严重偏向于Unicode(大多数Win32 API甚至没有ANSI等价物)。因此,CF也不能很好地使用ANSI,它需要一些“帮助”才能使其正确。
您可以通过使用MarshalAs属性(the MSDN docs清楚地表明它在CF中受支持)告诉编组程序您想要将数据作为单字节,空终止值传递,这些内容如下:< / p>
[DllImport("mydll.dll", SetLastError = true)]
public static extern void Foo([MarshalAs(UnmanagedType.LPStr)]string myString);
答案 2 :(得分:0)
我觉得这个marshal compiler很有用,即使它有点儿麻烦。