需求:启动一个WORD进程给用户操作,用户关闭进程后进行后续操作
一般处理方法,用ShellExecuteEx或者CreateProcess函数启动进程,然后等待进程退出。代码如下:
但是在用这种方式处理WORD的时间出现了一个大问题,当关闭WORD的时候,WORD进入了不响应状态,CPU占用率90%+,界面无法绘制,调用程序也失去响应。
在网上找资料,在大富翁论坛上有人讲到这个问题,他们是DELPHI的实现。把WaitForSingleObject的参数INFINATE改成一个特定的值,循环检测。
我比葫芦画瓢,只是C++中并没有Application.ProcessMessages这样的函数,我用Sleep(1000)来代替,发现并没有效果,而如果我在循环里面用MessageBox函数弹一个模式窗口而且不关掉这个窗口的话Word就可以正常关闭。看来原因不是在循环检测上面,而是在ProcessMessages处理了消息队列。由此猜测WORD关闭的时候要向调用者发消息并等待响应的原因,所以解决这个问题关键在于处理消息队列,即实现ProcessMessages的功能。
在BBS上一位仁兄的启发下我找到Delphi CLX框架的源码,然后读之,发现了三个关键的Windows API函数。
这个函数是分派收到的消息,检查线程的消息队列,并获取消息
这个函数是翻译实际的键盘消息为字符消息,字符消息送到该线程消息队列,用于下次调用GetMessage或者PeekMessage时读取。
这个函数将消息分派到窗口处理程序段。
最终的处理程序如下,这次没有WaitForSingleObject,而是使用了GetExitCodeProcess函数进程退出结果达到同样的轮询效果。
http://wking.ycool.com/post.680483.html
一般处理方法,用ShellExecuteEx或者CreateProcess函数启动进程,然后等待进程退出。代码如下:
m_localFilePath="C:\DocExc006926.doc"; SHELLEXECUTEINFO ShExecInfo ; memset(&ShExecInfo,0,sizeof(SHELLEXECUTEINFO)); ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = "open"; ShExecInfo.lpFile =(LPCTSTR)m_localFilePath; ShExecInfo.lpParameters = NULL; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_NORMAL; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); WaitForSingleObject(ShExecInfo.hProcess,INFINATE); |
但是在用这种方式处理WORD的时间出现了一个大问题,当关闭WORD的时候,WORD进入了不响应状态,CPU占用率90%+,界面无法绘制,调用程序也失去响应。
在网上找资料,在大富翁论坛上有人讲到这个问题,他们是DELPHI的实现。把WaitForSingleObject的参数INFINATE改成一个特定的值,循环检测。
While (WaitForSingleObject(ShExecInfo.hProcess,1000)=WAIT_TIMEOUT) do Application.ProcessMessages(); End |
我比葫芦画瓢,只是C++中并没有Application.ProcessMessages这样的函数,我用Sleep(1000)来代替,发现并没有效果,而如果我在循环里面用MessageBox函数弹一个模式窗口而且不关掉这个窗口的话Word就可以正常关闭。看来原因不是在循环检测上面,而是在ProcessMessages处理了消息队列。由此猜测WORD关闭的时候要向调用者发消息并等待响应的原因,所以解决这个问题关键在于处理消息队列,即实现ProcessMessages的功能。
在BBS上一位仁兄的启发下我找到Delphi CLX框架的源码,然后读之,发现了三个关键的Windows API函数。
BOOL PeekMessage( ); |
这个函数是分派收到的消息,检查线程的消息队列,并获取消息
BOOL TranslateMessage( ); |
这个函数是翻译实际的键盘消息为字符消息,字符消息送到该线程消息队列,用于下次调用GetMessage或者PeekMessage时读取。
LRESULT DispatchMessage( ); |
这个函数将消息分派到窗口处理程序段。
最终的处理程序如下,这次没有WaitForSingleObject,而是使用了GetExitCodeProcess函数进程退出结果达到同样的轮询效果。
m_localFilePath="C:\DocExc006926.doc"; SHELLEXECUTEINFO ShExecInfo ; memset(&ShExecInfo,0,sizeof(SHELLEXECUTEINFO)); ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = "open"; ShExecInfo.lpFile =(LPCTSTR)m_localFilePath; ShExecInfo.lpParameters = NULL; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_NORMAL; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); DWORD exCode; GetExitCodeProcess(ShExecInfo.hProcess,&exCode); while(exCode==STILL_ACTIVE) { Sleep(10); MSG msg; memset(&msg,0,sizeof(MSG)); if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } GetExitCodeProcess(ShExecInfo.hProcess,&exCode); } |