C# 传一个参数(带中文的字符串)给dll ,要求传UTF8,怎么传? utf8c#乱码 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 你那个dll到底要string还是char[ ]?还是byte[ ] 如果是string,其实跟编码没有关系...直接传就行了如果是传入byte[ ] 然后dll自己按UTF-8处理,你就string按UTF-8转byte[ ]传就好了 C#中字符串是没有编码之说的,转成byte[]时才会用到编码,就应该是这样做,参数改成byte[]或者intptr. 可以明确告诉您,有的!您可以试试在网上搜搜,然后自己试试,我这儿没时间贴代码。回复:Z65443344我不转化字符串编码,dll收到的就是乱码,所以感觉不能随便传。 怎么说呢,我觉得是没有编码的问题。在网上搜了一下,都是先转到byte在转到其他的编码。你试下反编译BLL,在用把BLL写成的类方式试下 那个dll是我自己写的,但是内容是抄的网上别人写的,所以不是很懂,只知道要传一个UTF8的参数给dll。至于将dll重写成类,我没有想过,也不想去试,有点多,太费时间了,所以改dll有点难,只有在C#传参上面做文章了。还请大神指导! 你应该先说明,什么叫做“一个UTF8的参数”。请你给出范例。要注意,.net平台里的字符串都是unicode编码的。 你只需要修改DLL的一行代码就是传参不要传string,而是传入byte[ ],然后再自己转string外部按UTF-8转byte[ ]传入DLL的方法里,就行了 这个参数变了,相应的函数处理也要变,而函数处理...我抄的,看不懂。 虽然我不太懂编码,也几乎没有研究过,所以导致今天的困扰。对于您说的“.net平台里的字符串都是unicode编码”,我个人觉得调用dll,String类型默认是ANSI编码(因为我调用System.Text.Encoding.Default时候,鼠标放在Default上,出现的是ANSI)。 至于范例:就是string str = “ 中国 ”,将str当做参数传给dll某个函数,而str必须是UTF8编码。否则,程序不执行那个函数,dll输出打印的信息为“参数不正确!” 我是说,你只修改传入的参数,具体参与处理还用string,但是是另一个局部变量,而不直接使用传入的参数这样不就好控制了么. 比如我的函数要求传入一个"2",然后参与处理现在我传入"2",它就变成了"5"那我先传入一个int型的2,dll自己将2转换成"2",然后再继续处理.就是这个意思 具体参与逻辑的地方,连变量名都不用改比如原先的函数是这样的:void function(string s){s...s...s....各种地方都用到s}我现在改成这样:void function(byte[ ] b){s=b(当然不是这么简单,要用对应的编码转)s...s...后面依然还用s,什么都不用改} 同意楼上的,DLL里面的函数,不需要你改动的,只需要在第一行加一个转换, 将byte[]转成String。 感谢:Z65443344但我还是想用C#来解决问题,因为C我只懂一点基本语法,可以说基本不会。而且我也遇到过dll由别人编写的情况,虽然那时候不需要考虑编码,但难保以后不会遇到,到时候总不能指望别人帮我把dll改了吧!所以我想从C#的角度解决该问题。 我已经能够将汉字传给dll,但是出现点问题,转化代码如下:charset设置为unicode,然后:static string str = System.Text.Encoding.unicode.GetString(System.Text.Encoding.Convert(System.Text.Encoding.Unicode,System.Text.Encoding.UTF8, System.Text.Encoding.Unicode.GetBytes("中国")));dll能够打印“中国”,虽然输出上是乱码,但是dll能够识别,程序能够运行。但是遇见了意外:如果传的字符串是英文,且最后一个是数字,那么最后那个数字不能识别,变成“?”如果传的字符串中有符号,最后一个字符也变成“?”不知道怎么解决?求助!! 简单的做传byte[]或者IntPtr就可以了。如果要好看传string,则比较复杂,要做CustomMarshaling。[DllImport(...)]extern static MyCall(byte[] str);void Test(){ byte[] str = Encoding.UTF8.GetBytes("中国 "); MyCall(str);} 额,楼上大哥,求教CustomMarshaling是什么东东?怎么整?至于传byte数组,我从来没有考虑过,也不打算考虑。我现在不急着等结果,但我更希望能学到东西,以后遇到会多一种解决方式。那个CustomMarshaling怎么搞?有资料吗?网站?连接?我想了解了解。 可以明确告诉您,有的!您可以试试在网上搜搜,然后自己试试,我这儿没时间贴代码。回复:Z65443344我不转化字符串编码,dll收到的就是乱码,所以感觉不能随便传。层主的意思你都没明白就开始胡乱否定...static string str = System.Text.Encoding.unicode.GetString(System.Text.Encoding.Convert(System.Text.Encoding.Unicode,System.Text.Encoding.UTF8, System.Text.Encoding.Unicode.GetBytes("中国")));你的这段代码我已经不想说什么了,先是把string转成Unicode字节形式,然后又转成UTF-8字节形式,然后又通过Unicode转换回string 此时已经是乱码了.... 其实此时没有乱码,只是转成unicode字符串的时候,最后一个字符会变成问号。因为unicode遇到连续两个‘\0’,才会认为终止,而static string str = System.Text.Encoding.unicode.GetString(byte【utf8】)只有一个'\0',所以乱码。在全是英文的时候,我加上一个'\0'就没有乱码,但是转中文又乱码了。而转中文不加“\0”,正常,所以,纠结。http://blog.csdn.net/ikok/article/details/8028803 至于最终转到utf8字符串,我只能呵呵,因为charset = unicode,所以dll压根儿不认识,虽然控制台输出正常,但是dll会认为乱码。 17楼,那个CustomMarshaling我想研究研究,感觉有戏! 还有一个问题:能不能将charset自定义成utf8(.net中charset只有四种枚举,ASNI,None,Auto和unicode,没有utf8,虽然unicode包含utf8,但是Windows中unicode默认是utf16,还是有区别的)。如果能将charset自定义成utf8的话,就简单了,一切问题迎刃而解了。但是我搜了很久,没有类似的记录,有人知道吗? class NativeMethods{ [DllImport("...")] extern static void MyFunc([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8StringMarshaler))]string str);}class UTF8StringMarshaler : ICustomMarshaler{ public void CleanUpManagedData(object ManagedObj) { } public void CleanUpNativeData(IntPtr pNativeData) { Marshal.FreeHGlobal(pNativeData); } public int GetNativeDataSize() { return -1; } public IntPtr MarshalManagedToNative(object ManagedObj) { if (object.ReferenceEquals(ManagedObj, null)) return IntPtr.Zero; if (!(ManagedObj is string)) throw new InvalidOperationException(); byte[] utf8bytes = Encoding.UTF8.GetBytes(ManagedObj as string); IntPtr ptr = Marshal.AllocHGlobal(utf8bytes.Length + 1); Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length); Marshal.WriteByte(ptr, utf8bytes.Length, 0); return ptr; } public object MarshalNativeToManaged(IntPtr pNativeData) { if (pNativeData == IntPtr.Zero) return null; List<byte> bytes = new List<byte>(); for (int offset = 0; ; offset++) { byte b = Marshal.ReadByte(pNativeData, offset); if (b == 0) break; else bytes.Add(b); } return Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count); }} 字符串只有在转换为字节序列的时候,才有编码一说。所以 C++ 的 dll 要求的不是 C# 里面的 string,而是 byte[],所以要重新定义 Dll 的导出函数。这样,使用 Encoding 转换为 UTF8 的 字节序列,直接传递给 Dll。 String 类 表示文本,即一系列 Unicode 字符。 下面纯属个人编程感觉: 对于“字符串只有在转换为字节序列的时候,才有编码一说。”个人不太认同,因为.net平台自动将编码转换,编码统一,让我们少了很多麻烦,同时也让我们误解,字符串没有编码一说。 至于您说的传byte[ ],虽然现在我可以这么做,但是日后团队开发怎么办?团队不会为您一个人去改dll接口,每个人都有自己的分工,他只要UTF8的字符串,您就只能传字符串。其他人不会为您一个人该接口,甚至您都不知道找谁去修改。 我没有点评您什么,只是单纯的想解决这个情况,为今后做打算,我希望我能进步,也希望以后看到这封帖子的人有个参考。因为我之前花了不少时间找相关的资料,但是没什么结果。 不过,感谢您的参与,让这封帖子多了一分生气。 回复:gomoku有异常,我尝试解决,但是说实话,您的代码太高深,看不懂,解决不了。 团队开发,就必须考虑通用性不同开发语言,不同编码格式,必须找一个共有的类型来传递否则我就写成你必须传一个datatable进来,你要使用VC或VB,还没法调用了. 对,团队开发一般通用编码UTF8,因为他应用最广。 class UTF8StringMarshaler : ICustomMarshaler{ public void CleanUpManagedData(object ManagedObj) { } public void CleanUpNativeData(IntPtr pNativeData) { Marshal.FreeHGlobal(pNativeData); } public int GetNativeDataSize() { return -1; } public IntPtr MarshalManagedToNative(object ManagedObj) { if (object.ReferenceEquals(ManagedObj, null)) return IntPtr.Zero; if (!(ManagedObj is string)) throw new InvalidOperationException(); byte[] utf8bytes = Encoding.UTF8.GetBytes(ManagedObj as string); IntPtr ptr = Marshal.AllocHGlobal(utf8bytes.Length + 1); Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length); Marshal.WriteByte(ptr, utf8bytes.Length, 0); return ptr; } public object MarshalNativeToManaged(IntPtr pNativeData) { if (pNativeData == IntPtr.Zero) return null; List<byte> bytes = new List<byte>(); for (int offset = 0; ; offset++) { byte b = Marshal.ReadByte(pNativeData, offset); if (b == 0) break; else bytes.Add(b); } return Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count); } // 添加以下静态GetInstance方法 static UTF8StringMarshaler instance = new UTF8StringMarshaler(); public static ICustomMarshaler GetInstance(string cookie) { return instance; } // 以上添加} void Test(){ byte[] str = Encoding.UTF8.GetBytes("中国" + (char)0); // 更正,要加结束零。 MyCall(str);}跟ICustomMarshaler比,你觉得那个更简单? 与传递byte数组而言,我更喜欢ICustomMarshaler,因为他可以让我多一种处理方法,个人觉得我们是程序员,有些甚至是工程师,还有些甚至更牛X的。我们这些研发人员不是要求别人去改接口,而是需要自己动手解决问题,这才叫研发人员。 感谢gomoku,感谢Z65443344,感谢诸位,问题好像解决了,我还需要进一步测试。 该给分了,人人有份,当然,有人多,有人少,结贴了! 有一关于分页的疑问,请解答 c#怎样能让用panel控件做的窗体最小化 如何脱离死循环 有关c#高级编程系列技术专题 ! 请帮忙看一下同步显示问题 .net 编写的程序,打包后安装,安装後在有VS2005环境下可以运行,只有FRAMEWORK2.0环境下出错的问题 多进程难题问高手啊!没有多少分了,大家帮忙啊!! 存储过程中能不能写循环语句!急!进进! 请教高人Process类传参调用winform windows API 获取窗体的所有子窗体代码 win7系统如何获取托盘图标的Tooltips 怎么用C#制作透明横幅广播效果
如果是传入byte[ ] 然后dll自己按UTF-8处理,你就string按UTF-8转byte[ ]传就好了
回复:Z65443344
我不转化字符串编码,dll收到的就是乱码,所以感觉不能随便传。
在网上搜了一下,都是先转到byte在转到其他的编码。
你试下反编译BLL,在用把BLL写成的类方式试下
你应该先说明,什么叫做“一个UTF8的参数”。请你给出范例。要注意,.net平台里的字符串都是unicode编码的。
就是传参不要传string,而是传入byte[ ],然后再自己转string
外部按UTF-8转byte[ ]传入DLL的方法里,就行了
虽然我不太懂编码,也几乎没有研究过,所以导致今天的困扰。对于您说的“.net平台里的字符串都是unicode编码”,我个人觉得调用dll,String类型默认是ANSI编码(因为我调用System.Text.Encoding.Default时候,鼠标放在Default上,出现的是ANSI)。
至于范例:就是string str = “ 中国 ”,将str当做参数传给dll某个函数,而str必须是UTF8编码。否则,程序不执行那个函数,dll输出打印的信息为“参数不正确!”
这样不就好控制了么.
现在我传入"2",它就变成了"5"
那我先传入一个int型的2,dll自己将2转换成"2",然后再继续处理.
就是这个意思
比如原先的函数是这样的:
void function(string s)
{
s...s...s....各种地方都用到s
}
我现在改成这样:
void function(byte[ ] b)
{
s=b(当然不是这么简单,要用对应的编码转)
s...s...后面依然还用s,什么都不用改
}
但我还是想用C#来解决问题,因为C我只懂一点基本语法,可以说基本不会。而且我也遇到过dll由别人编写的情况,虽然那时候不需要考虑编码,但难保以后不会遇到,到时候总不能指望别人帮我把dll改了吧!所以我想从C#的角度解决该问题。
charset设置为unicode,然后:
static string str = System.Text.Encoding.unicode.GetString(System.Text.Encoding.Convert(System.Text.Encoding.Unicode,System.Text.Encoding.UTF8, System.Text.Encoding.Unicode.GetBytes("中国")));
dll能够打印“中国”,虽然输出上是乱码,但是dll能够识别,程序能够运行。
但是遇见了意外:如果传的字符串是英文,且最后一个是数字,那么最后那个数字不能识别,变成“?”
如果传的字符串中有符号,最后一个字符也变成“?”
不知道怎么解决?
求助!!
如果要好看传string,则比较复杂,要做CustomMarshaling。[DllImport(...)]
extern static MyCall(byte[] str);void Test()
{
byte[] str = Encoding.UTF8.GetBytes("中国 ");
MyCall(str);
}
至于传byte数组,我从来没有考虑过,也不打算考虑。
我现在不急着等结果,但我更希望能学到东西,以后遇到会多一种解决方式。
那个CustomMarshaling怎么搞?有资料吗?网站?连接?我想了解了解。
回复:Z65443344
我不转化字符串编码,dll收到的就是乱码,所以感觉不能随便传。层主的意思你都没明白就开始胡乱否定...static string str = System.Text.Encoding.unicode.GetString(System.Text.Encoding.Convert(System.Text.Encoding.Unicode,System.Text.Encoding.UTF8, System.Text.Encoding.Unicode.GetBytes("中国")));
你的这段代码我已经不想说什么了,先是把string转成Unicode字节形式,然后又转成UTF-8字节形式,然后又通过Unicode转换回string 此时已经是乱码了....
http://blog.csdn.net/ikok/article/details/8028803
至于最终转到utf8字符串,我只能呵呵,因为charset = unicode,所以dll压根儿不认识,虽然控制台输出正常,但是dll会认为乱码。
17楼,那个CustomMarshaling我想研究研究,感觉有戏!
{
[DllImport("...")]
extern static void MyFunc([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8StringMarshaler))]string str);
}class UTF8StringMarshaler : ICustomMarshaler
{
public void CleanUpManagedData(object ManagedObj)
{
} public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
} public int GetNativeDataSize()
{
return -1;
} public IntPtr MarshalManagedToNative(object ManagedObj)
{
if (object.ReferenceEquals(ManagedObj, null)) return IntPtr.Zero;
if (!(ManagedObj is string)) throw new InvalidOperationException();
byte[] utf8bytes = Encoding.UTF8.GetBytes(ManagedObj as string);
IntPtr ptr = Marshal.AllocHGlobal(utf8bytes.Length + 1);
Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length);
Marshal.WriteByte(ptr, utf8bytes.Length, 0);
return ptr;
} public object MarshalNativeToManaged(IntPtr pNativeData)
{
if (pNativeData == IntPtr.Zero) return null;
List<byte> bytes = new List<byte>();
for (int offset = 0; ; offset++)
{
byte b = Marshal.ReadByte(pNativeData, offset);
if (b == 0) break;
else bytes.Add(b);
}
return Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count);
}
}
所以 C++ 的 dll 要求的不是 C# 里面的 string,而是 byte[],所以要重新定义 Dll 的导出函数。
这样,使用 Encoding 转换为 UTF8 的 字节序列,直接传递给 Dll。
表示文本,即一系列 Unicode 字符。
对于“字符串只有在转换为字节序列的时候,才有编码一说。”个人不太认同,因为.net平台自动将编码转换,编码统一,让我们少了很多麻烦,同时也让我们误解,字符串没有编码一说。
至于您说的传byte[ ],虽然现在我可以这么做,但是日后团队开发怎么办?团队不会为您一个人去改dll接口,每个人都有自己的分工,他只要UTF8的字符串,您就只能传字符串。其他人不会为您一个人该接口,甚至您都不知道找谁去修改。
我没有点评您什么,只是单纯的想解决这个情况,为今后做打算,我希望我能进步,也希望以后看到这封帖子的人有个参考。因为我之前花了不少时间找相关的资料,但是没什么结果。
不过,感谢您的参与,让这封帖子多了一分生气。
不同开发语言,不同编码格式,必须找一个共有的类型来传递否则我就写成你必须传一个datatable进来,你要使用VC或VB,还没法调用了.
{
public void CleanUpManagedData(object ManagedObj)
{
} public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
} public int GetNativeDataSize()
{
return -1;
} public IntPtr MarshalManagedToNative(object ManagedObj)
{
if (object.ReferenceEquals(ManagedObj, null)) return IntPtr.Zero;
if (!(ManagedObj is string)) throw new InvalidOperationException();
byte[] utf8bytes = Encoding.UTF8.GetBytes(ManagedObj as string);
IntPtr ptr = Marshal.AllocHGlobal(utf8bytes.Length + 1);
Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length);
Marshal.WriteByte(ptr, utf8bytes.Length, 0);
return ptr;
} public object MarshalNativeToManaged(IntPtr pNativeData)
{
if (pNativeData == IntPtr.Zero) return null;
List<byte> bytes = new List<byte>();
for (int offset = 0; ; offset++)
{
byte b = Marshal.ReadByte(pNativeData, offset);
if (b == 0) break;
else bytes.Add(b);
}
return Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count);
}
// 添加以下静态GetInstance方法
static UTF8StringMarshaler instance = new UTF8StringMarshaler();
public static ICustomMarshaler GetInstance(string cookie)
{
return instance;
}
// 以上添加
}
{
byte[] str = Encoding.UTF8.GetBytes("中国" + (char)0); // 更正,要加结束零。
MyCall(str);
}
跟ICustomMarshaler比,你觉得那个更简单?
感谢gomoku,感谢Z65443344,感谢诸位,问题好像解决了,我还需要进一步测试。
该给分了,人人有份,当然,有人多,有人少,结贴了!