ShellExecuteEx启动WORD进程关不掉的处理

来源:互联网 发布:干部网络培训挂机软件 编辑:程序博客网 时间:2024/05/17 00:52
需求:启动一个WORD进程给用户操作,用户关闭进程后进行后续操作
一般处理方法,用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(
 LPMSG lpMsg,         // message information
 HWND hWnd,           // handle to window
 UINT wMsgFilterMin,  // first message
 UINT wMsgFilterMax,  // last message
 UINT wRemoveMsg      // removal options
);

这个函数是分派收到的消息,检查线程的消息队列,并获取消息

BOOL TranslateMessage(
 CONST MSG *lpMsg   // message information
);

这个函数是翻译实际的键盘消息为字符消息,字符消息送到该线程消息队列,用于下次调用GetMessage或者PeekMessage时读取。

LRESULT DispatchMessage(
 CONST MSG *lpmsg   // message information
);

这个函数将消息分派到窗口处理程序段。

最终的处理程序如下,这次没有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);
}
http://wking.ycool.com/post.680483.html
0 0
原创粉丝点击