DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: tkzcol
今日帖子: 38
在线用户: 5
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 iamcws (你健康我快乐) ★☆☆☆☆ -
普通会员
2016/12/12 14:05:04
标题:
SendNotifyMessage从线程发送消息到主窗体时,主窗体收到的消息经常会出现乱码或收到的消息比发送时的少了,如何解决?谢谢! 浏览:1659
加入我的收藏
楼主: 使用SendNotifyMessage在线程中发送消息到主窗体时主窗体收到的消息经常会出现乱码或收到的消息比发送时的少了。
线程发送消息:
strMsg := '对象不存在';
SendNotifyMessage(iHwnd, UM_SHOWREADWRITE, WParam(Length(strMsg)), Lparam(PChar(strMsg)));
主窗体收到消息:
procedure TMainForm.ShowReadWrite(Var Msg: TMessage); //列:行索引列表=数据
var
  dwSize: DWORD;
  Smessage: String;
begin
  try
    dwsize := DWORD(Msg.wParam);
    SetLength(Smessage, dwSize);
    Move(PChar(Msg.lParam)^, PChar(Smessage)^, dwsize);
    ......
  except
  end;
end;
Smessage的值经常会是“对象不存”或“对象不?”之类的。
请教各位老师,有没有遇到上面的问题?如何解决?谢谢!
----------------------------------------------
不要等到孤独寂寞时才想起朋友,不要等到穷困潦倒时才想起发奋,不要等到疾病缠身时才想起健康。。。
作者:
男 ghs_79 (ghs) ★☆☆☆☆ -
盒子活跃会员
2016/12/12 17:30:43
1楼: 不知道你的环境如何,我这里使用很正常。D7+WIN10
----------------------------------------------
Delphi爱好者。
作者:
男 nevergrief (孤独骑士) ★☆☆☆☆ -
盒子活跃会员
2016/12/12 17:51:56
2楼: 把源代码存为UTF8试试

另外,Move命令好像只能以Byte为单位拷贝,所以你用PCHAR为单位好像是错的,改成PAnsiChar试试(不管你什么版本Delphi)
----------------------------------------------
只有偏执狂才能生存!
作者:
男 iamcws (你健康我快乐) ★☆☆☆☆ -
普通会员
2016/12/12 19:18:37
3楼: 非常感谢nevergrief (孤独骑士)老师的回复,改成PAnsiChar结果是一样的。你是说在线程中把发送的消息存为UTF8格式的字符串?如何存成UTF8格式的字符串?请指教!谢谢!
----------------------------------------------
不要等到孤独寂寞时才想起朋友,不要等到穷困潦倒时才想起发奋,不要等到疾病缠身时才想起健康。。。
作者:
男 jccddd (jcd) ★☆☆☆☆ -
普通会员
2016/12/12 20:44:48
4楼: Smessage: ^String;
用指针试试,发送消息前,用堆变量别用栈变量,处理完消息后,再删除指针指向的内存。
----------------------------------------------
-上帝给我们的脑子编程,我们给电脑编程,可上帝却始终站在电脑一边...
作者:
男 nevergrief (孤独骑士) ★☆☆☆☆ -
盒子活跃会员
2016/12/12 21:27:15
5楼: 右键设置源码格式为UTF8.

其实还是同一个问题,我假设你你使用2009以后的高版本Delphi,那么你的
WParam(Length(strMsg))
计算字符串长度结果为5,但占了10个字节。
也就是此时你的dwsize=5

然而Move的单位是byte,这样拷贝5个byte,肯定内容不全啊。
修改办法,直接使用:
    dwsize := DWORD(Msg.wParam);
    SetLength(Smessage, dwSize); // 这样设置宽字符串,还是5
    Move(PAnsiChar(Msg.lParam)^, PAnsiChar(Smessage)^, dwsize*2); // 对5个字符的宽字符串,拷贝的byte是10,而且指针类型理应是PAnsiChar
这样最简单明了。

下次提问记得说清楚你用哪个版本的Delphi,搞得一堆假设,不能有针对性解决问题。
----------------------------------------------
只有偏执狂才能生存!
作者:
男 bdl1 (bdl1) ▲▲▲▲▲ -
普通会员
2016/12/13 11:10:49
6楼: 用SizeOf计算长度,再试试...
----------------------------------------------
-我的博客
作者:
男 iamcws (你健康我快乐) ★☆☆☆☆ -
普通会员
2016/12/14 9:58:36
7楼: 非常感谢各位老师的热情回复,我用的是Delphi7。使用PAnsiChar和PChar是一样的结果,使用dwsize*2会报错更不行。使用用SizeOf计算长度也会报错。Smessage: ^String;这种方式如何使用,能不能写出简单代码,谢谢!
----------------------------------------------
不要等到孤独寂寞时才想起朋友,不要等到穷困潦倒时才想起发奋,不要等到疾病缠身时才想起健康。。。
作者:
男 iamdream (银河恒久远,梦想无止境!) ★☆☆☆☆ -
大贡献会员
2016/12/14 10:28:33
8楼:  在线程里用SendNotifyMessage向主窗体发送消息后将会立即返回,也就是字符串马上会被释放掉,因为它们不在同一线程里,你这种情况建议用SendMessage;
当然,主窗体里的消息接收函数也可以简化一下:
procedure TMainForm.ShowReadWrite(Var Msg: TMessage); //列:行索引列表=数据
var
  Smessage: String;
begin
  Smessage := StrPas(PChar(Msg.LParam));
  ......
end;

如果你一定要用SendNotifyMessage,那么请用GetMem/AllocMem之类的函数申请内存后传递字符串,在接收处释放内存,不过如果消息没送达,则可能会有内存泄漏,当然也可以用复杂些的内存管理。
----------------------------------------------
-广袤璀璨的银河,永无止境的梦想(梦无止境游银河) 博客挂了……
作者:
男 wr960204 (武稀松) ★☆☆☆☆ -
盒子活跃会员
2016/12/14 12:44:02
9楼: 楼上说的对的,SendNotifyMessage单线程类似SendMessage是同步的,多线程操作是异步的,类似POSTMessage。
题主SendNotifyMessage发完消息就继续往下执行了,这个时候你发送的字符串内容可能已经变了,甚至内存已经被回收了。所以接收方如果处理的比你后面的稍微慢的话,就会导致拿到的内容是错乱的,甚至会有访问不可读内存地址的问题。

改成SendMessage,同步执行就不会有问题了,或者像楼上说的,发送方分配内存,接收方释放就没问题了。
----------------------------------------------
武稀松http://www.raysoftware.cn
作者:
男 jccddd (jcd) ★☆☆☆☆ -
普通会员
2016/12/14 13:19:30
10楼: const
  UM_SHOWREADWRITE = WM_USER+1;
type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure OnShowReadWrite(var message:TMessage);message UM_SHOWREADWRITE;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  pStrMsg:^string;
begin
  new(pStrMsg);
  pStrMsg^:='Hello,world';
  SendNotifyMessage(Handle,UM_SHOWREADWRITE,0,LPARAM(pStrMsg));
end;

procedure TForm1.OnShowReadWrite(var message: TMessage);
var
  pStrMsg:^string;
begin
  pStrMsg := Pointer(message.LParam);
  Memo1.Text := pStrMsg^;
  Dispose(pStrMsg);
end;
----------------------------------------------
-上帝给我们的脑子编程,我们给电脑编程,可上帝却始终站在电脑一边...
作者:
男 iamcws (你健康我快乐) ★☆☆☆☆ -
普通会员
2016/12/15 11:32:11
11楼: 非常感谢各位老师的热情回复,按照jccddd (jcd)老师的方法,已经OK了,谢谢!
----------------------------------------------
不要等到孤独寂寞时才想起朋友,不要等到穷困潦倒时才想起发奋,不要等到疾病缠身时才想起健康。。。
作者:
男 lab01 (lab01) ★☆☆☆☆ -
盒子活跃会员
2016/12/15 22:53:43
12楼: LZ问的不是多线程的场景吗,怎么没看出jccddd老师的多线程?LZ你到底问的是什么?
----------------------------------------------
-
作者:
男 lab01 (lab01) ★☆☆☆☆ -
盒子活跃会员
2016/12/15 22:55:04
13楼: iamdream才是正解!把var message:string设为全局的即可
----------------------------------------------
-
作者:
男 jccddd (jcd) ★☆☆☆☆ -
普通会员
2016/12/16 14:55:25
14楼: 本示例不是要演示多线程,而是应楼主的要求,写个简单的代码演示如何在非堵塞式消息函数中传递对象,这也是多线程传递消息必需的,如果用全局变量,那是另一回事了。如果将SendNotifyMessage换成PostMessage,你就能理解这段代码的意思了。
----------------------------------------------
-上帝给我们的脑子编程,我们给电脑编程,可上帝却始终站在电脑一边...
作者:
男 jccddd (jcd) ★☆☆☆☆ -
普通会员
2016/12/16 14:58:41
15楼: 当函数返回时,局部变量会被销毁,用全局变量是一种不被看好的编程风格。要想将string类的对象通过消息传递到另一个函数,在堆中创建对象是一种简单的方法,同时需要注意的是对象要在处理完后,别忘了销毁。
----------------------------------------------
-上帝给我们的脑子编程,我们给电脑编程,可上帝却始终站在电脑一边...
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行750毫秒 RSS