Delphi7 中Ansi To Unicode的问题,不知道是哪里有问题

光明的猪 2016-12-27 12:02:45
本人在做一个使用中国移动CMPP3.0协议收发短信的工具,因移动短信网关 只支持Unicode的编码格式。所以在收短信的时候我使用了:

function TMainForm.My_UniCodeArrayToString(Content: PChar; Size: Integer): string;
var
R: PWord;
P: PByteArray;
W: WideString;
Offset: Integer;
begin
P := PByteArray(Content);
Size := Size div 2;
SetLength(W, Size);
Offset := 0;
R := PWord(W);
while Size > 0 do
begin
R^ := P^[Offset] * 256 + P^[Offset + 1];
Inc(R);
Dec(Size);
Inc(Offset, 2);
end;
Result := W;
end;


将网关发送过来的UniCode转换为String.这里是正常的,可以入库为中文短信。

现在问题是:在向网关发送短信的时候,需要把数据库里的String转成UniCode,
我在网上找了一段看似没问题的代码,如下:
function AnsiToUnicode(Str: AnsiString): String;
var
Len: integer;
begin
Len := Length(Str)+ 1;
SetLength(Result, Len);
Len := MultiByteToWideChar(CP_ACP, 0, PAnsiChar(Str),-1,
PWideChar(Result), Len);
SetLength(Result, Len- 1); // end is #0
end;

可是在F9的时候,提示:
[警告] MainUnit.pas(218): Suspicious typecast of String to PWideChar
[警告] MainUnit.pas(461): Comparison always evaluates to False
[错误] MainUnit.pas(995): Statement expected but 'FUNCTION' found
[警告] MainUnit.pas(1002): Suspicious typecast of String to PWideChar
[错误] MainUnit.pas(1006): Declaration expected but identifier 'AShortMessage' found
[错误] MainUnit.pas(1013): '.' expected but ';' found

请问:这是代码问题还是写法有问题?
请使用function TMainForm.My_UniCodeArrayToString(Content: PChar; Size: Integer): string;的写法写个StringtoUniCode的类,谢谢!
...全文
1015 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
武稀松 2017-01-06
  • 打赏
  • 举报
回复
其实Delphi的ANSIString和WideString你直接赋值就可以内部转换。里面调用的也是MultiByteToWideChar
光明的猪 2017-01-03
  • 打赏
  • 举报
回复
引用 17 楼 DelphiGuy 的回复:
啊,有一个问题: Move(Content^, PWideChar(Result)^, Len * SizeOf(WideChar));
出差了两天,今天回来看了一下,手机向网关发短信,再入库是没有问题了。 不过,程序发送给网关的,网关再转发给手机,手机收到的还是乱码 如下: function AnsiToUnicodeBE(S: AnsiString): WideString; var i: integer; begin Result := S; for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end; zhuyanw:= AnsiToUnicodeBE(AShortMessage);
  • 打赏
  • 举报
回复
我写的UnicodeBEToString是把unicode大端编码的字符串转换为widestring(小端编码)、AnsiToUnicodeBE是把ansistring转换为unicode大端编码的字符串,就我的测试是功能正常的,但是你的网关收发涉及到很多协议的东西,不仅是字符编码,这需要你自己测试,别人帮不上什么忙。比如“程序发送给网关的,网关再转发给手机,手机收到的还是乱码”,是某型手机,还是所有手机,你也可以让网关把转发给手机乱码的信息发给你的程序,dump出来看看接收的原始数据是什么样子的。
  • 打赏
  • 举报
回复
啊,有一个问题: Move(Content^, PWideChar(Result)^, Len * SizeOf(WideChar));
  • 打赏
  • 举报
回复
由于不了解从网关收到的信息是否包含正确的NULL终止,稍微修改一下。 测试代码: function UnicodeBEToString(Content: PWideChar; Len: integer): WideString; // 修改了,增加了指定长度(unicode字符数量) var i: integer; begin SetLength(Result, Len); Move(Content^, PWideChar(Result)^, Len); for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end; function AnsiToUnicodeBE(S: AnsiString): WideString; var i: integer; begin Result := S; for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end; procedure TForm1.Button1Click(Sender: TObject); const Data: array[0..11] of byte = ($8f, $d9, $66, $2f, $4e, $00, $4e, $2a, $6d, $4b, $8b, $d5); // unicode big endian编码的"这是一个测试",你可以把从网关收到的信息原始数据放到这里测试 content: PChar = @Data; var s: WideString; s1: ANsiString; begin s := PWideChar(content); Label1.Caption := s; // 乱码 s := UnicodeBEToString(PWideChar(content), 6); Label2.Caption := s; // 这是一个测试 s1 := s; Label3.Caption := AnsiToUnicodeBE(s); // 转换回unicode big endian编码 end;
光明的猪 2016-12-30
  • 打赏
  • 举报
回复
引用 13 楼 DelphiGuy 的回复:
[quote=引用 12 楼 zyqabcaa 的回复:] 会不会是你理解错了。 CMPP3只能使用 if PK_CMPP_DELIVER.Msg_Fmt in [8..11, 23..25, 27] then //UCS2 begin ShortMessage := self.My_UniCodeArrayToString(PK_CMPP_DELIVER_CONTENT.Msg_Content,PK_CMPP_DELIVER.Msg_Length) end; msg=8即UCS2编码来发送和接收短信。 我先表述一下,我所理解的所谓的发和收的定义 收信息,指的是手机收到网关发来的信息 发信息,指的是手机向网关发送的信息 现在发信息正常。 再来表述一下我所理解的发和收的过程 收信息:手机向1065XXXXXX的号码发送信息,网关接收到信息后,返回接收的数据,再由我所写的工具存入数据库。 发信息:先把信息内容、即将发送的手机号码先写入数据库(GB编码),工具从数据库里读取:信息内容、手机号、msg=8(UCS2编码格式)等,向网关发送,网关必须接收的是UCS2编码才予以放行。网关再把收到的内容发送给指定的手机号码。 不知道我表述清楚了吗? 而您给的代码是把Unicode 码转为String的过程,这个是收信息的过程啊,我前面说过,这个过程是正常的。 目前的问题是,如果把我放到数据库里的信息内容转化为UCS2编码发给网关。 谢谢!
没错呀,我说的就是这个收发,#11写的function UnicodeBEToString(S: PWideChar): WideString;是用于显示接收到的信息(注意不是用你顶楼My_UniCodeArrayToString处理过的信息,是原始数据),可以替换My_UniCodeArrayToString,而#4写的function AnsiToUnicodeBE(S: AnsiString): WideString;是用于发送之前处理编码的,比如: var s: AnsiString; w: WideString; begin s := '这是一个测试。xyz'; w := AnsiToUnicodeBE(s); send(w); // 或者send(PWideChar(w), Length(w)); 假设这里的send是你用的发送信息的函数 end; [/quote] 手机收到网关发过来的短信还是乱码,具体代码请见14楼
光明的猪 2016-12-29
  • 打赏
  • 举报
回复
procedure TMainForm.LoopTimerTimer(Sender: TObject); var CMPP_SUBMIT : TCMPP_SUBMIT; //AShortMessage: string; AShortMessage: AnsiString;//朱颜 zhuyanw: WideString; begin if not self.CMPP3Socket.Active then Exit;; if not My_LoginFlag then Exit; try (Sender AS TTimer).Enabled := false; self.Query1.Close; self.Query1.SQL.Text := 'SELECT TOP ' + IntToStr(self.My_MaxRecCount) + ' * FROM Submit WHERE MT_SendCount = 0'; self.CDS1.Open; self.CDS1.First; while not self.CDS1.Eof do begin if not self.CMPP3Socket.Active then Break; FillChar(CMPP_SUBMIT,SizeOf(CMPP_SUBMIT),0); with CMPP_SUBMIT do begin Msg_Id := CDS1.FieldByName('Msg_Id').AsInteger; Pk_total := Byte(CDS1.FieldByName('Pk_total').AsInteger); Pk_number := Byte(CDS1.FieldByName('Pk_number').AsInteger); Registered_Delivery := Byte(CDS1.FieldByName('Registered_Delivery').AsInteger); Msg_level := Byte(CDS1.FieldByName('Msg_level').AsInteger); My_StrCopy(trim(CDS1.FieldByName('Service_Id').AsString),Service_Id,SizeOf(Service_Id)); Fee_UserType := Byte(CDS1.FieldByName('Fee_UserType').AsInteger); My_StrCopy(trim(CDS1.FieldByName('Fee_terminal_Id').AsString),Fee_terminal_Id,SizeOf(Fee_terminal_Id)); Fee_terminal_type := Byte(CDS1.FieldByName('Fee_terminal_type').AsInteger); TP_pId := Byte(CDS1.FieldByName('TP_pId').AsInteger) ; TP_udhi := Byte(CDS1.FieldByName('TP_udhi').AsInteger); Msg_Fmt := Byte(CDS1.FieldByName('Msg_Fmt').AsInteger); My_StrCopy(My_SPCorpID,Msg_src,SizeOf(Msg_src)); My_StrCopy(trim(CDS1.FieldByName('FeeType').AsString),FeeType,SizeOf(FeeType)); My_StrCopy(trim(CDS1.FieldByName('FeeCode').AsString),FeeCode,SizeOf(FeeCode)); if trim(CDS1.FieldByName('ValId_Time').AsString) <> '' then begin My_StrCopy(trim(CDS1.FieldByName('ValId_Time').AsString),ValId_Time,SizeOf(CMPP_SUBMIT.ValId_Time)); end; if trim(CDS1.FieldByName('At_Time').AsString) <> '' then begin My_StrCopy(trim(CDS1.FieldByName('At_Time').AsString),At_Time,SizeOf(CMPP_SUBMIT.At_Time)); end; My_StrCopy(trim(CDS1.FieldByName('Src_Id').AsString),Src_Id,SizeOf(Src_Id)); DestUsr_tl := 1; My_StrCopy(trim(CDS1.FieldByName('Dest_terminal_Id').AsString),Dest_terminal_Id,SizeOf(Dest_terminal_Id)); Dest_terminal_type := Byte(CDS1.FieldByName('Dest_terminal_type').AsInteger); //AShortMessage := trim(self.CDS1.FieldByName('Msg_Content').AsString);//朱颜 AShortMessage := '1234567890ABC';//朱颜 zhuyanw:= My_AnsiToUnicodeBE(AShortMessage); if CMPP_SUBMIT.Msg_Fmt = 0 then AShortMessage := Copy(AShortMessage,1,159) else AShortMessage := Copy(zhuyanw,1,140); if My_CanPackBadWord = '1' then AShortMessage := self.My_PackBadWord(AShortMessage); Msg_Length := Length(AShortMessage); My_StrCopy(AShortMessage,Msg_Content,Length(Msg_Content)); My_StrCopy(trim(CDS1.FieldByName('LinkID').AsString),LinkID,SizeOf(LinkID)); end; self.CMPP3_SUBMIT(CMPP_SUBMIT,CDS1.FieldByName('ID').AsString); self.CDS1.Delete; Application.ProcessMessages; self.My_DelayTime; end; finally self.CDS1.Close; self.Query1.Close; (Sender AS TTimer).Enabled := true; end; end; 我觉得以上代码没有错误了啊,可是收到的仍然是乱码!!!!我都无语了!完全按你的方法做的啊
  • 打赏
  • 举报
回复
引用 12 楼 zyqabcaa 的回复:
会不会是你理解错了。 CMPP3只能使用 if PK_CMPP_DELIVER.Msg_Fmt in [8..11, 23..25, 27] then //UCS2 begin ShortMessage := self.My_UniCodeArrayToString(PK_CMPP_DELIVER_CONTENT.Msg_Content,PK_CMPP_DELIVER.Msg_Length) end; msg=8即UCS2编码来发送和接收短信。 我先表述一下,我所理解的所谓的发和收的定义 收信息,指的是手机收到网关发来的信息 发信息,指的是手机向网关发送的信息 现在发信息正常。 再来表述一下我所理解的发和收的过程 收信息:手机向1065XXXXXX的号码发送信息,网关接收到信息后,返回接收的数据,再由我所写的工具存入数据库。 发信息:先把信息内容、即将发送的手机号码先写入数据库(GB编码),工具从数据库里读取:信息内容、手机号、msg=8(UCS2编码格式)等,向网关发送,网关必须接收的是UCS2编码才予以放行。网关再把收到的内容发送给指定的手机号码。 不知道我表述清楚了吗? 而您给的代码是把Unicode 码转为String的过程,这个是收信息的过程啊,我前面说过,这个过程是正常的。 目前的问题是,如果把我放到数据库里的信息内容转化为UCS2编码发给网关。 谢谢!
没错呀,我说的就是这个收发,#11写的function UnicodeBEToString(S: PWideChar): WideString;是用于显示接收到的信息(注意不是用你顶楼My_UniCodeArrayToString处理过的信息,是原始数据),可以替换My_UniCodeArrayToString,而#4写的function AnsiToUnicodeBE(S: AnsiString): WideString;是用于发送之前处理编码的,比如: var s: AnsiString; w: WideString; begin s := '这是一个测试。xyz'; w := AnsiToUnicodeBE(s); send(w); // 或者send(PWideChar(w), Length(w)); 假设这里的send是你用的发送信息的函数 end;
  • 打赏
  • 举报
回复
你前面不是说接收正常吗,怎么又成乱码了。
光明的猪 2016-12-28
  • 打赏
  • 举报
回复
引用 11 楼 DelphiGuy 的回复:
我写的这个并不是用于接收的,而是发送之前处理一下编码,你理解错了。 编码处理过之后已经变成unicode大端格式了,你再显示出来就成乱码了,因为WideString对应Windows的BSTR,固定是小端格式UTF-16,D7又不支持TEncoding,否则指定BigEndianUnicode 就可以正确显示。 要显示处理过的字符串,可以这样(也可以用于接收): function UnicodeBEToString(S: PWideChar): WideString; var i: integer; begin Result := S; for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end;
会不会是你理解错了。 CMPP3只能使用 if PK_CMPP_DELIVER.Msg_Fmt in [8..11, 23..25, 27] then //UCS2 begin ShortMessage := self.My_UniCodeArrayToString(PK_CMPP_DELIVER_CONTENT.Msg_Content,PK_CMPP_DELIVER.Msg_Length) end; msg=8即UCS2编码来发送和接收短信。 我先表述一下,我所理解的所谓的发和收的定义 收信息,指的是手机收到网关发来的信息 发信息,指的是手机向网关发送的信息 现在发信息正常。 再来表述一下我所理解的发和收的过程 收信息:手机向1065XXXXXX的号码发送信息,网关接收到信息后,返回接收的数据,再由我所写的工具存入数据库。 发信息:先把信息内容、即将发送的手机号码先写入数据库(GB编码),工具从数据库里读取:信息内容、手机号、msg=8(UCS2编码格式)等,向网关发送,网关必须接收的是UCS2编码才予以放行。网关再把收到的内容发送给指定的手机号码。 不知道我表述清楚了吗? 而您给的代码是把Unicode 码转为String的过程,这个是收信息的过程啊,我前面说过,这个过程是正常的。 目前的问题是,如果把我放到数据库里的信息内容转化为UCS2编码发给网关。 谢谢!
光明的猪 2016-12-28
  • 打赏
  • 举报
回复
现在不报错了,不过收到的短信是乱码!!! 看了一些文档,说要把GB码转为UCS2编码。
  • 打赏
  • 举报
回复
我写的这个并不是用于接收的,而是发送之前处理一下编码,你理解错了。 编码处理过之后已经变成unicode大端格式了,你再显示出来就成乱码了,因为WideString对应Windows的BSTR,固定是小端格式UTF-16,D7又不支持TEncoding,否则指定BigEndianUnicode 就可以正确显示。 要显示处理过的字符串,可以这样(也可以用于接收): function UnicodeBEToString(S: PWideChar): WideString; var i: integer; begin Result := S; for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end;
光明的猪 2016-12-28
  • 打赏
  • 举报
回复
function AnsiToUnicodeBE(S: AnsiString): WideString; var i: integer; begin Result := S; for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end; AShortMessage :=AnsiToUnicodeBE( trim(self.CDS1.FieldByName('Msg_Content').AsString)); 收到的短信为乱码
lyhoo163 2016-12-28
  • 打赏
  • 举报
回复
要贴全代码,别人才能帮助你。
光明的猪 2016-12-27
  • 打赏
  • 举报
回复
自已顶一下吧,高手在哪里
光明的猪 2016-12-27
  • 打赏
  • 举报
回复
引用 1 楼 lyhoo163 的回复:
代码中有的要使用PWideChar,而不是WideString。
function AnsiToUnicode(Str: AnsiString): String;
var
  Len: integer;
begin
  Len := Length(Str)+ 1;
  SetLength(Result, Len);
  Len := MultiByteToWideChar(CP_ACP, 0, PAnsiChar(Str),-1,
    PWideChar(Result), Len);
  SetLength(Result, Len- 1); // end is #0
end;
问题出在这段上面
光明的猪 2016-12-27
  • 打赏
  • 举报
回复
引用 4 楼 DelphiGuy 的回复:
function AnsiToUnicode这个根本没必要,直接两种类型互相赋值就自动转换了。 唯一的问题是从前面的代码 R^ := P^[Offset] * 256 + P^[Offset + 1]; 来看,移动短信网关使用的unicode编码是大端格式,所以需要转换一下: function AnsiToUnicodeBE(S: AnsiString): WideString; var i: integer; begin Result := S; for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end; 然后直接发送这个函数返回的WideString就可以了。
现在不报错了,可以正常收到短信了,不过收到的短信为乱码。
lyhoo163 2016-12-27
  • 打赏
  • 举报
回复
代码中有的要使用PWideChar,而不是WideString。
santiaodahan 2016-12-27
  • 打赏
  • 举报
回复
把function AnsiToUnicode(Str: AnsiString): String;的返回类型修改为WideString,即function AnsiToUnicode(Str: AnsiString): WideString;有些错误不是这个函数的。
  • 打赏
  • 举报
回复
function AnsiToUnicode这个根本没必要,直接两种类型互相赋值就自动转换了。 唯一的问题是从前面的代码 R^ := P^[Offset] * 256 + P^[Offset + 1]; 来看,移动短信网关使用的unicode编码是大端格式,所以需要转换一下: function AnsiToUnicodeBE(S: AnsiString): WideString; var i: integer; begin Result := S; for i := 1 to Length(Result) do Result[i] := WideChar(Swap(word(Result[i]))); end; 然后直接发送这个函数返回的WideString就可以了。

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧