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

http://blog.csdn.net/ysai/article/details/7468961

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

(by ysai)

现象:

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

 

原因:

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

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

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

 

演示代码:

[delphi] view plain copy
 
  1. TTestThread = class(TThread)  
  2. private  
  3.   procedure ProcessMessages;  
  4. protected  
  5.   procedure Execute; override;  
  6. end;  
  7.   
  8. procedure TTestThread.Execute;  
  9. begin  
  10.   TTimer.Create(nil);  //TTimer会创建隐藏的窗口  
  11.   while not Terminated do  
  12.   begin  
  13.     DoSomething;//线程干活  
  14.     //ProcessMessages;  //去掉这一句就可能卡死  
  15.     Sleep(1);  
  16.   end;  
  17. end;  
  18.   
  19. ///内建的一个简单消息循环  
  20. procedure TTestThread.ProcessMessages;  
  21. var  
  22.   Msg: TMsg;  
  23. begin  
  24.   while PeekMessage(Msg, 0, 0, 0,PM_REMOVE) then  
  25.   begin  
  26.     TranslateMessage(Msg);  
  27.     DispatchMessage(Msg);  
  28.   end;  
  29. end;  

 

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

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

 

终极解决方案:

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

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

[delphi] view plain copy
 
  1. procedure FreeIMEWindow;  
  2. const  
  3.   IME_WINDOW_CLASS ='IME';  
  4.   IME_WINDOW_TEXT = 'Default IME';  
  5. var  
  6.   h : HWND;  
  7.   pid : DWORD;  
  8.   dh : HWND;  
  9. begin  
  10.   if GetCurrentThreadId= 主线程IDthen exit;    //如果是主线程,那么它应该有消息循环,可以不处理  
  11.   h := FindWindow(IME_WINDOW_CLASS, IME_WINDOW_TEXT);  
  12.   while IsWindow(h) do  
  13.   begin  
  14.     ifGetWindowThreadProcessId(h, pid) = GetCurrentThreadId then  
  15.       dh  :=  h  
  16.     else  
  17.       dh  :=  0;  
  18.     h:=  FindWindowEx(0, h, IME_WINDOW_CLASS, IME_WINDOW_TEXT);  
  19.     if dh<> then  
  20.       DestroyWindow(dh);  
  21.   end;  
  22. end;  
  23.   
  24. procedure TTestThread.Execute;  
  25. begin  
  26.   TTimer.Create(nil);  //TTimer会创建隐藏的窗口    
  27.   FreeIMEWindow;  //释放IME窗口  
  28.   while not Terminated do  
  29.   begin  
  30.     DoSomething;//线程干活  
  31.     Sleep(1);  
  32.   end;  
  33. end; 
posted @ 2016-10-17 16:02  德芙70  阅读(1220)  评论(0编辑  收藏  举报