Windows 编程: 将目标窗口显示在最顶端

1. [BUG Backgroud]

  1. 使用SetForegroundWindow(hwnd) 不能将目标窗口弹到顶端.
  2. Win7 中使用WIN键后出现的BUG.

最终成功测试代码:html

BOOL MyClass::PutMyWindowToTop(
) {
  OutputDebugString("In function PutMyWindowToTop!");
  HWND hwnd = FindWindow(NULL, L"MyWindow");
  if (hwnd == NULL) {
      OutputDebugString("Failed to get hwnd of MyWindow!");
      return FALSE;
  } else {
      OutputDebugString("Success get hwnd of MyWindow before switch to window");
  }
  if (!::IsWindow(hwnd)) {
      OutputDebugString("hwnd is not a valid window's handler!");
      return FALSE;
  }
  try {
      DWORD lock_timeout = 0;
      DWORD lock_timeout_after = 0;
      HWND  current_hwnd = ::GetForegroundWindow();
      DWORD dw_this_tid = ::GetCurrentThreadId();
      DWORD dw_current_tid = ::GetWindowThreadProcessId(current_hwnd, 0);
      if (dw_this_tid != dw_current_tid) {
          ::AttachThreadInput(dw_this_tid, dw_current_tid, TRUE);

          ::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &lock_timeout, 0);
          if (lock_timeout >= 100) {
             ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
             if (0 == ::AllowSetForegroundWindow(dw_this_tid)) {
                 OutputDebugString("Failed to AllowSetForegoundWindow!");
             } else {
                 OutputDebugString("Successed in AllowSetForegoundWindow!");
             }
             ::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &lock_timeout_after, 0);
          }
      }
      char temp_s[60] = { 0 };
      sprintf(temp_s, "lock_timeout: %u, after: %u", lock_timeout, lock_timeout_after);
      OutputDebugString(temp_s);
      //Test SetWindows position.
      if (0 == ::ShowWindow(hwnd, SW_SHOWNORMAL)) {
          OutputDebugString("ShowWindow return window was previously hidden!");
      } else {
          OutputDebugString("ShowWindow return window was previously visible!");
      }
      if (0 == ::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE)) {
          OutputDebugString("SetWindowPos first time was failed!");
      } else {
          OutputDebugString("SetWindowPos first time was succeed!");
      }
      if (0 == ::SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE)) {
          OutputDebugString("SetWindowPos second time was failed!");
      } else {
          OutputDebugString("SetWindowPos second time was succeed!");
      }
      
      if (0 == ::SetForegroundWindow(hwnd)) {
          OutputDebugString("Failed to set this window to foreground!");
      } else {
          OutputDebugString("Success in set this window to foreground!");
      }

      if (dw_this_tid != dw_current_tid) {
          ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)lock_timeout, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
          ::AttachThreadInput(dw_this_tid, dw_current_tid, FALSE);
      }
  } catch (...) {
      OutputDebugString("Failed to put MyWindow window to top!");
  }

  OutputDebugString("End function PutMyWindowToTop!");

  return TRUE;
}

2. 最终分析

SetForegroundWindow 其实并不进行窗口z-order 次序的更改, 它所作的事就是像人同样在任务栏上点击了一下程序. https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setforegroundwindowweb

经过最后的调试结果来看, 设置不设置Foreground time out 参数对结果没有影响. 相应的代码能够去掉. 这个感受是个老问题, 在论坛上找到了好多的讨论, 可是并不知道为何. 这个还得大神来.windows

另外: SetActiveWindow是干什么的? 获取输入队列?api

related website:svg

  1. 将后台窗口激活到前台的方法(使用AttachThreadInput和SetForegroundWindow两个API)–>这个在大多数状况下都是能够的, 可是在少数特定状况下不知道为何不能够.
  2. SetForegroundWindow的正确用法 --> 就是按照这个来的, 恕我愚钝, 没有看出来缘由.
  3. SetForegroundWindow、SetActiveWindow、SetFocus 如何将一个某个窗口提到最顶层

3. others:

  1. 在pdf, EXCEL 文件中设置超连接时, 路径上不能有#字符.
  2. CSDN的MarkDown 编辑界面好用了一些, 可是为何代码段用黑色背景, 感受不配啊! (虽然我在编辑代码的时候用黑色的! 哼!)