XP下切换输入法造成程序卡死的原因及解决方案

XP下切换输入法造成程序卡死的原因及解决方案

(by ysai)

现象:

在XP下,如果线程中创建了窗口而线程中没有消息循环,那么可能切换输入法时会造成程序卡死(某些XP下必现,跟安装盘有关)

 

原因:

线程创建一个窗口后,系统会自动创建一个Default IME窗口以便通知输入法消息(可能只有可以接收输入的窗口才会创建,未证实)

XP下切换输入法,会向所有DefaultIME窗口SendMessage告诉应用程序,当前输入法改变了

而线程窗口如果没有消息循环,则不会处理消息队列,然后卡死

 

演示代码:

TTestThread = class(TThread)
private
  procedure ProcessMessages;
protected
  procedure Execute; override;
end;

procedure TTestThread.Execute;
begin
  TTimer.Create(nil);  //TTimer会创建隐藏的窗口
  while not Terminated do
  begin
    DoSomething;//线程干活
    //ProcessMessages;  //去掉这一句就可能卡死
    Sleep(1);
  end;
end;

///内建的一个简单消息循环
procedure TTestThread.ProcessMessages;
var
  Msg: TMsg;
begin
  while PeekMessage(Msg, 0, 0, 0,PM_REMOVE) then
  begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
end;

程序中使用上面的线程,则在XP下切换输入法可能卡死

即使线程中加入了消息循环,如果在线程工作时DoSomething占用过多时间,也会假死

 

终极解决方案:

如果不能避免在线程中创建窗口(比如调用了某个COM组件,但COM内部创建了窗口,如ADO会创建一个ADODB.AsyncEventMessenger窗口)

则在线程创建窗口后,执行以下代码

procedure FreeIMEWindow;
const
  IME_WINDOW_CLASS ='IME';
  IME_WINDOW_TEXT = 'Default IME';
var
  h : HWND;
  pid : DWORD;
  dh : HWND;
begin
  if GetCurrentThreadId= 主线程IDthen exit;    //如果是主线程,那么它应该有消息循环,可以不处理
  h := FindWindow(IME_WINDOW_CLASS, IME_WINDOW_TEXT);
  while IsWindow(h) do
  begin
    ifGetWindowThreadProcessId(h, pid) = GetCurrentThreadId then
      dh  :=  h
    else
      dh  :=  0;
    h:=  FindWindowEx(0, h, IME_WINDOW_CLASS, IME_WINDOW_TEXT);
    if dh<> 0 then
      DestroyWindow(dh);
  end;
end;

procedure TTestThread.Execute;
begin
  TTimer.Create(nil);  //TTimer会创建隐藏的窗口  
  FreeIMEWindow;  //释放IME窗口
  while not Terminated do
  begin
    DoSomething;//线程干活
    Sleep(1);
  end;
end;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值