Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining if a Window Has a Taskbar Button

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.

like image 271
Synetech Avatar asked Feb 14 '10 20:02

Synetech


People also ask

How do I show the window in the taskbar?

If ShowInTaskbar is set to true, the window will also appear in the ALT+TAB application selection list. The icon that is used for both the task bar button and the ALT+TAB application selection list is the value of the Icon property. You cannot set or get this property when a window is hosted in a browser.

How do I put a button on the taskbar in shell?

Managing Taskbar Buttons 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.

How do I remove a button from the taskbar?

As an alternative, you can create a hidden window and make this hidden window the owner of your visible window. The Shell will remove a window's button from the taskbar only if the window's style supports visible taskbar buttons.

What are the icons used for the taskbar button and tab?

The icon that is used for both the task bar button and the ALT+TAB application selection list is the value of the Icon property. You cannot set or get this property when a window is hosted in a browser.


3 Answers

  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.

like image 53
pulp Avatar answered Oct 29 '22 07:10

pulp


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.

like image 36
John Knoeller Avatar answered Oct 29 '22 06:10

John Knoeller


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.

like image 33
Unsigned Avatar answered Oct 29 '22 06:10

Unsigned