views:

220

answers:

2

Hi,

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.

+4  A: 

Windows uses hueristics to decide to give a taskbar button to a window, and sometimes it doesn't figure it out for a while, so to do this perfectly accurately is going to be quite hard. but here's a rough start on the rules. There a 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 of WS_OVERLAPPED suggests TASKBAR
  • Style of WS_POPUP suggests NOT_TASKBAR especially if GetParent() is non-null
  • ExStyle of WS_EX_OVERLAPPEDWINDOW suggests TASKBAR
  • ExStyle of WS_EX_CLIENTEDGE or 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.

John Knoeller
Wow, it looks like this is one of those frustrating things that turns out to not be straightforward… “guessing”? :( Thanks for the info; I’ll give it a shot tonight.
Synetech inc.
+2  A: 
  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.

pulp
Lovely, thanks for the extra info and code. I’ll give it a shot tonight.
Synetech inc.