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

发布于 2024-08-22 02:08:03 字数 187 浏览 7 评论 0原文

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

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

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

非常感谢。

I am looking for a way to check if a given window has a taskbar button. That is, given a handle to a window, I need a TRUE if the window is in the taskbar, and FALSE otherwise.

Conversely, I am wondering if there is a way to get a handle to the window that belongs to a given taskbar button, which I suppose would require a way to enumerate through the taskbar buttons.

(The first former is the part that I need, and the latter part is optional.)

Thanks a lot.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

盗琴音 2024-08-29 02:08:03

Windows 使用启发式方法来决定是否为窗口提供任务栏按钮,有时在决定之前会存在延迟,因此 100% 准确地做到这一点将非常困难。这是规则的粗略开始。有一些现代风格的标志可以让你很容易知道,但是当这些风格缺失时,任务栏就只能靠猜测了。

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

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

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

  • 如果ExStyle & WS_EX_APPWINDOW,则 TASKBAR
  • 如果 ExStyle & WS_EX_TOOLWINDOW
  • 如果 Style & 则为 NOT_TASKBAR 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 版本的不同而发生了变化。

Windows uses heuristics to decide whether or not to give a taskbar button to a window, and sometimes there is a delay before it can decide, so doing this 100% accurately is going to be quite hard. Here's a rough start on the rules. There are modern style flags that make it easy to know, but when those styles are missing the taskbar is reduced to guessing.

First off, you will need both of the the window style flags.

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

Now the rules, there are three rules that are certain.

  • if ExStyle & WS_EX_APPWINDOW, then TASKBAR
  • if ExStyle & WS_EX_TOOLWINDOW, then NOT_TASKBAR
  • if Style & WS_CHILD then NOT_TASKBAR

The rest are guesses:

  • Style & WS_OVERLAPPED suggests TASKBAR
  • Style & WS_POPUP suggests NOT_TASKBAR especially if GetParent() != NULL
  • ExStyle & WS_EX_OVERLAPPEDWINDOW suggests TASKBAR
  • ExStyle & WS_EX_CLIENTEDGE suggests NOT_TASKBAR
  • ExStyle & WS_EX_DLGMODALFRAME suggests NOT_TASKBAR

I'm sure that there are other rules for guessing, and in fact that the guessing rules have changed from version to version of Windows.

东风软 2024-08-29 02:08:03
  1. 顶级窗口

  2. WS_EX_APPWINDOW ->任务栏,无论其他样式!

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

  4. 否:WS_EX_NOACTIVATE 或 WS_EX_TOOLWINDOW:

顺序很重要。

第二个问题:在 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 中不再可能。所以你需要循环所有顶层窗口。

  1. Toplevel window

  2. WS_EX_APPWINDOW -> taskbar, no matter the other styles!

  3. OWNER must be NULL (GetWindow(window, GW_OWNER))

  4. no: WS_EX_NOACTIVATE or WS_EX_TOOLWINDOW:

order is important.

second question: in windows xp/vista it was possible to get into the process of the taskbar and get all window ID´s:

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);
    }
  }
}

this not possible with windows 7 anymore. so you need to loop over all toplevel windows.

烟火散人牵绊 2024-08-29 02:08:03

这篇 MSDN 文章 有一些关于 Shell 何时以及为何决定为窗口创建任务栏按钮的有用信息:

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

This MSDN article has some good information about when and why the Shell decides to create a taskbar button for a window:

The Shell creates a button on the taskbar whenever an application creates a window that isn't owned. To ensure that the window button is placed on the taskbar, create an unowned window with the WS_EX_APPWINDOW extended style. To prevent the window button from being placed on the taskbar, create the unowned window with the WS_EX_TOOLWINDOW extended style. As an alternative, you can create a hidden window and make this hidden window the owner of your visible window.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文