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

时间:2022-11-16 13:13:23
本人在做一个使用中国移动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的类,谢谢!

20 个解决方案

#1


代码中有的要使用PWideChar,而不是WideString。

#2


引用 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;
问题出在这段上面

#3


自已顶一下吧,高手在哪里

#4


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就可以了。

#5


把function AnsiToUnicode(Str: AnsiString): String;的返回类型修改为WideString,即function AnsiToUnicode(Str: AnsiString): WideString;有些错误不是这个函数的。

#6


引用 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就可以了。

现在不报错了,可以正常收到短信了,不过收到的短信为乱码。

#7


现在不报错了,不过收到的短信是乱码!!!

看了一些文档,说要把GB码转为UCS2编码。

#8


你前面不是说接收正常吗,怎么又成乱码了。

#9


要贴全代码,别人才能帮助你。

#10


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));

收到的短信为乱码

#11


我写的这个并不是用于接收的,而是发送之前处理一下编码,你理解错了。
编码处理过之后已经变成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;

#12


引用 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编码发给网关。

谢谢!

#13


引用 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;

#14


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;

我觉得以上代码没有错误了啊,可是收到的仍然是乱码!!!!我都无语了!完全按你的方法做的啊

#15


引用 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;

手机收到网关发过来的短信还是乱码,具体代码请见14楼

#16


由于不了解从网关收到的信息是否包含正确的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;

#17


啊,有一个问题:
Move(Content^, PWideChar(Result)^, Len  * SizeOf(WideChar));

#18


引用 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);

#19


我写的UnicodeBEToString是把unicode大端编码的字符串转换为widestring(小端编码)、AnsiToUnicodeBE是把ansistring转换为unicode大端编码的字符串,就我的测试是功能正常的,但是你的网关收发涉及到很多协议的东西,不仅是字符编码,这需要你自己测试,别人帮不上什么忙。比如“程序发送给网关的,网关再转发给手机,手机收到的还是乱码”,是某型手机,还是所有手机,你也可以让网关把转发给手机乱码的信息发给你的程序,dump出来看看接收的原始数据是什么样子的。

#20


其实Delphi的ANSIString和WideString你直接赋值就可以内部转换。里面调用的也是MultiByteToWideChar

#1


代码中有的要使用PWideChar,而不是WideString。

#2


引用 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;
问题出在这段上面

#3


自已顶一下吧,高手在哪里

#4


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就可以了。

#5


把function AnsiToUnicode(Str: AnsiString): String;的返回类型修改为WideString,即function AnsiToUnicode(Str: AnsiString): WideString;有些错误不是这个函数的。

#6


引用 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就可以了。

现在不报错了,可以正常收到短信了,不过收到的短信为乱码。

#7


现在不报错了,不过收到的短信是乱码!!!

看了一些文档,说要把GB码转为UCS2编码。

#8


你前面不是说接收正常吗,怎么又成乱码了。

#9


要贴全代码,别人才能帮助你。

#10


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));

收到的短信为乱码

#11


我写的这个并不是用于接收的,而是发送之前处理一下编码,你理解错了。
编码处理过之后已经变成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;

#12


引用 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编码发给网关。

谢谢!

#13


引用 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;

#14


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;

我觉得以上代码没有错误了啊,可是收到的仍然是乱码!!!!我都无语了!完全按你的方法做的啊

#15


引用 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;

手机收到网关发过来的短信还是乱码,具体代码请见14楼

#16


由于不了解从网关收到的信息是否包含正确的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;

#17


啊,有一个问题:
Move(Content^, PWideChar(Result)^, Len  * SizeOf(WideChar));

#18


引用 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);

#19


我写的UnicodeBEToString是把unicode大端编码的字符串转换为widestring(小端编码)、AnsiToUnicodeBE是把ansistring转换为unicode大端编码的字符串,就我的测试是功能正常的,但是你的网关收发涉及到很多协议的东西,不仅是字符编码,这需要你自己测试,别人帮不上什么忙。比如“程序发送给网关的,网关再转发给手机,手机收到的还是乱码”,是某型手机,还是所有手机,你也可以让网关把转发给手机乱码的信息发给你的程序,dump出来看看接收的原始数据是什么样子的。

#20


其实Delphi的ANSIString和WideString你直接赋值就可以内部转换。里面调用的也是MultiByteToWideChar

#21