0

我的应用程序(我正在处理的安装程序的引导应用程序需要启动一些其他应用程序(我的安装程序和第三方安装程序,用于我的安装程序的先决条件)并等待它们完成。为了允许 GUI 进行屏幕更新在等待应用程序完成时,我使用 Visual Studio 文档中关于空闲循环处理的“MFC 兼容”示例作为指导,在等待循环中放置了一个消息泵。我的代码(位于 CWinApp 的成员函数中-派生类)如下:

if (::CreateProcess(lpAppName, szCmdLineBuffer, NULL, NULL, TRUE, 0, NULL, NULL,
                    &StartupInfo, &ProcessInfo))
{
  ::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
  if (bWait)
    while (dwExitCode == STILL_ACTIVE)
    {
      // In order to allow updates of the GUI to happen while we're waiting for
      // the application to finish, we must run a mini message pump here to
      // allow messages to go through and get processed.  This message pump
      // performs much like MFC's main message pump found in CWinThread::Run().
      MSG msg;
      while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
      {
        if (!PumpMessage())
        {
          // a termination message (e.g. WM_DESTROY)
          // was processed, so we need to stop waiting
          dwExitCode = ERROR_CANT_WAIT;
          ::PostQuitMessage(0);
          break;
        }
      }

      // let MFC do its idle processing
      LONG nIdle = 0;
      while (OnIdle(nIdle++))
        ;

      if (dwExitCode == STILL_ACTIVE) // was a termination message processed?
      {
        // no; wait for .1 second to see if the application is finished
        ::WaitForSingleObject(ProcessInfo.hProcess, 100);
        ::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
      }
    }
  ::CloseHandle(ProcessInfo.hProcess);
  ::CloseHandle(ProcessInfo.hThread);
}
else
  dwExitCode = ::GetLastError();

我遇到的问题是,在某些时候,此消息泵似乎释放了我在运行此代码时打开的窗口上的窗口和菜单句柄。我在调试器中进行了遍历,它从来没有进入 if (!PumpMessage()) 语句的主体,所以我不知道这里发生了什么导致窗口和菜单句柄消失南。如果我没有消息泵,一切正常,只是在等待循环运行时 GUI 无法自行更新。

有没有人对如何使这项工作有任何想法?或者,如果 bWait 为 TRUE,我想启动一个工作线程来启动第二个应用程序,但我以前从未对线程做过任何事情,所以我需要一些关于如何在不引入同步问题等的情况下做到这一点的建议.(无论哪种情况,代码示例都将不胜感激。)

4

4 回答 4

2

我还在 Microsoft 论坛上发布了这个问题,感谢 Microsoft 的 Doug Harris 的帮助,我发现我的 HWND 和 HMENU 值的问题确实是由于过时的 CWwnd* 和 CMenu* 指针(使用获得GetMenu() 和 GetDialogItem() 调用。在启动第二个应用程序后再次获取指针解决了这个问题。此外,他向我指出了一个网站*,该网站显示了使用 MsgWaitForMultipleObjects() 进行循环的更好方法来控制它'不涉及等待一段时间并轮询进程以获取退出代码的繁忙工作。

我的循环现在看起来像这样:

if (bWait)
{
  // In order to allow updates of the GUI to happen while we're
  // waiting for the application to finish, we must run a message
  // pump here to allow messages to go through and get processed.
  LONG  nIdleCount = 0;
  for (;;)
  {
    MSG msg;
    if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
      PumpMessage();
    else //if (!OnIdle(nIdleCount++))
    {
      nIdleCount = 0;
      if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
      {
        DWORD nRes = ::MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess,
                                                 FALSE, INFINITE, QS_ALLEVENTS);
        if (nRes == WAIT_OBJECT_0)
          break;
      }
    }
  }
}
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);

*如果您好奇,该网站是: http: //members.cox.net/doug_web/threads.htm

于 2009-05-07T16:42:23.227 回答
1

我认为你的问题在于WaitForSingleObject

MSDN中你会看到这个

调用直接或间接创建窗口的等待函数和代码时要小心。如果线程创建任何窗口,它必须处理消息。消息广播被发送到系统中的所有窗口。使用没有超时间隔的等待函数的线程可能会导致系统死锁。间接创建窗口的两个代码示例是 DDE 和 CoInitialize 函数。因此,如果您有创建窗口的线程,请使用 MsgWaitForMultipleObjects 或 MsgWaitForMultipleObjectsEx,而不是 WaitForSingleObject。

在我的消息泵代码中使用 use MsgWaitForMultipleObjects( doc )。

用一个电话这个电话。

MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess, FALSE, 100, QS_ALLEVENTS); 

这应该可以解决资源消失的问题。

于 2009-05-07T00:35:55.717 回答
0

当您说窗口和菜单句柄似乎被释放时,您的意思是您的实际 HWND 和 HMENU 值似乎不再有效,还是您的 MFC CWnd* 和 CMenu* 变量失败?

如果是后者,问题很可能是您通过在某处调用 CWnd::FromHandle() (或 CMenu::FromHandle())(或调用调用它们的东西)来获取 CWnd* 指针,而 OnIdle() 是丢弃它们。

根本原因是 MFC 维护了一个从窗口(或菜单等)句柄到系统中 CWnd* 对象的映射。当调用 CWnd::FromHandle() 时,它会在映射中查找匹配项:如果找到,则返回。如果不是,则创建一个新的临时 CWnd,将其添加到地图中并返回。OnIdle() 背后的想法是,当它被调用时,所有消息处理都已完成,因此 OnIdle() 丢弃任何仍然存在的临时 CWnd 对象。这就是为什么 CWnd::FromHandle() 文档警告返回的指针可能是临时的。

对此的“正确”解决方案是不要挂在从 CWnd::FromHandle() 返回的 CWnd* 指针上。鉴于您的应用程序的简单性,删除调用 OnIdle() 可能会更容易:这不会对安装程序产生任何负面影响。

当然,这全是猜测,但听起来似乎很合理……

于 2009-05-07T08:08:03.290 回答
0

There is a Windows function called DisableProcessWindowsGhosting (see http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx) that prevents Windows from 'ghosting' your window, and continue updating the window (your animation).

于 2011-12-08T08:32:08.413 回答