确定窗口是否具有任务栏按钮

时间:2010-02-14 20:56:12

标签: windows taskbar

我正在寻找一种检查给定窗口是否有任务栏按钮的方法。也就是说,给定窗口的句柄,如果窗口在任务栏中,我需要为TRUE,否则为FALSE。

相反,我想知道是否有办法获取属于给定任务栏按钮的窗口的句柄,我想这需要一种方法来枚举任务栏按钮。

(第一个前者是我需要的部分,后者是可选的。)

非常感谢。

3 个答案:

答案 0 :(得分:11)

Windows使用启发式方法来决定是否将任务栏按钮提供给窗口,有时在确定之前会有延迟,因此这样做100%准确将会非常困难。这是规则的粗略开始。现代风格的标志让人们很容易知道,但是当缺少这些风格时,任务栏就会减少猜测。

首先,你需要两个窗口样式标志。

LONG Style = GetWindowLong(hwnd, GWL_STYLE);
LONG ExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);

现在的规则,有三个规则是肯定的。

  • 如果ExStyle & WS_EX_APPWINDOW,则为TASKBAR
  • 如果ExStyle & WS_EX_TOOLWINDOW,则为NOT_TASKBAR
  • if Style & WS_CHILD然后NOT_TASKBAR

剩下的就是猜测:

  • Style & WS_OVERLAPPED建议使用TASKBAR
  • Style & WS_POPUP建议使用NOT_TASKBAR,尤其是GetParent() != NULL
  • ExStyle & WS_EX_OVERLAPPEDWINDOW建议使用TASKBAR
  • ExStyle & WS_EX_CLIENTEDGE建议使用NOT_TASKBAR
  • ExStyle & WS_EX_DLGMODALFRAME建议使用NOT_TASKBAR

我确信还有其他猜测规则,实际上猜测规则已经从Windows的版本更改为版本。

答案 1 :(得分:7)

  1. Toplevel窗口

  2. WS_EX_APPWINDOW - >任务栏,无论其他风格如何!

  3. OWNER必须为NULL(GetWindow(窗口,GW_OWNER))

  4. no:WS_EX_NOACTIVATE或WS_EX_TOOLWINDOW:

  5. 顺序很重要。

    第二个问题:在windows xp / vista中,可以进入任务栏的进程并获取所有窗口ID:

    void EnumTasklistWindows()
    {
      int b2 = 0;
      TBBUTTON tbButton;
      DWORD dwProcessId = 0, dwThreadId = 0;
    
      HWND hDesktop =::GetDesktopWindow();
      HWND hTray =::FindWindowEx(hDesktop, 0, ("Shell_TrayWnd"), NULL);
      HWND hReBar =::FindWindowEx(hTray, 0, ("ReBarWindow32"), NULL);
      HWND hTask =::FindWindowEx(hReBar, 0, ("MSTaskSwWClass"), NULL);
      HWND hToolbar =::FindWindowEx(hTask, 0, ("ToolbarWindow32"), NULL);
    
      LRESULT count =::SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0);
      dwThreadId = GetWindowThreadProcessId(hToolbar, &dwProcessId);
    
      shared_ptr<void> hProcess (OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId), CloseHandle);
      if (NULL == hProcess.get())
      {
        return;
      }
    
      memset(&tbButton, 0, sizeof(TBBUTTON));
    
      for (int i = 0; i < count; i++)
      {
        memset(&tbButton, 0, sizeof(TBBUTTON));
    
        shared_ptr<void> lpRemoteBuffer (
          VirtualAllocEx(hProcess.get(), NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE), 
          bind<BOOL>(VirtualFreeEx, hProcess.get(), _1, 0, MEM_RELEASE));
        if (NULL == lpRemoteBuffer.get())
        {
          return;
        }
    
        SendMessage(hToolbar, TB_GETBUTTON, i, (LPARAM) lpRemoteBuffer.get());
    
        b2 = ReadProcessMemory(hProcess.get(), lpRemoteBuffer.get(),
          (LPVOID) & tbButton, sizeof(TBBUTTON), NULL);
        if (0 == b2)
        {
          continue;
        }
    
        BYTE localBuffer[0x1000];
        BYTE *pLocalBuffer = localBuffer;
        DWORD_PTR ipLocalBuffer = (DWORD_PTR) pLocalBuffer;
        pLocalBuffer = localBuffer;
        ipLocalBuffer = (DWORD_PTR) pLocalBuffer;
        DWORD_PTR lpRemoteData = (DWORD_PTR) tbButton.dwData;
    
        ReadProcessMemory(hProcess.get(), (LPVOID) lpRemoteData, (LPVOID) ipLocalBuffer,
          sizeof(DWORD_PTR), NULL);
    
        HWND windowHandle;
        memcpy(&windowHandle, (void *) ipLocalBuffer, 4);
    
        if (windowHandle != NULL)
        {
          trace ("adding button: %x\n", windowHandle);
        }
      }
    }
    

    这不再适用于Windows 7了。所以你需要遍历所有的顶层窗口。

答案 2 :(得分:1)

This MSDN article提供了一些关于Shell决定为窗口创建任务栏按钮的时间和原因的一些很好的信息:

  

只要应用程序创建了一个不属于的窗口,Shell就会在任务栏上创建一个按钮。要确保窗口按钮位于任务栏上,请使用WS_EX_APPWINDOW扩展样式创建无主窗口。要防止窗口按钮放在任务栏上,请使用WS_EX_TOOLWINDOW扩展样式创建无主窗口。作为替代方案,您可以创建一个隐藏窗口,并使此隐藏窗口成为可见窗口的所有者。