http://blog.csdn.net/ysai/article/details/7468961
XP下切换输入法造成程序卡死的原因及解决方案
(by ysai)
现象:
在XP下,如果线程中创建了窗口而线程中没有消息循环,那么可能切换输入法时会造成程序卡死(某些XP下必现,跟安装盘有关)
原因:
线程创建一个窗口后,系统会自动创建一个Default IME窗口以便通知输入法消息(可能只有可以接收输入的窗口才会创建,未证实)
XP下切换输入法,会向所有DefaultIME窗口SendMessage告诉应用程序,当前输入法改变了
而线程窗口如果没有消息循环,则不会处理消息队列,然后卡死
演示代码:
[delphi] view plain copy
- 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窗口)
则在线程创建窗口后,执行以下代码
[delphi] view plain copy
- 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;
时间: 2024-10-17 06:53:56