11

特定のウィンドウにタスクバー ボタンがあるかどうかを確認する方法を探しています。つまり、ウィンドウへのハンドルが与えられた場合、ウィンドウがタスクバーにある場合は TRUE が必要であり、それ以外の場合は FALSE が必要です。

逆に、特定のタスクバー ボタンに属するウィンドウへのハンドルを取得する方法があるかどうか疑問に思っています。これには、タスクバー ボタンを列挙する方法が必要になると思います。

(最初の前者は私が必要な部分で、後者の部分はオプションです。)

どうもありがとう。

4

3 に答える 3

11

Windowsはヒューリスティックを使用して、ウィンドウにタスクバーボタンを与えるかどうかを決定します。また、決定するまでに遅延が発生する場合があるため、これを100%正確に行うことは非常に困難です。これがルールの大まかなスタートです。わかりやすくするモダンなスタイルのフラグがありますが、それらのスタイルが欠落している場合、タスクバーは推測になります。

まず、両方のウィンドウスタイルフラグが必要になります。

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

今ルール、確かな3つのルールがあります。

  • の場合ExStyle & WS_EX_APPWINDOW、タスクバー
  • の場合ExStyle & WS_EX_TOOLWINDOW、NOT_TASKBAR
  • もしそうならStyle & WS_CHILDNOT_TASKBAR

残りは推測です:

  • Style & WS_OVERLAPPEDタスクバーを提案します
  • Style & WS_POPUP特に次の場合にNOT_TASKBARを提案しますGetParent() != NULL
  • ExStyle & WS_EX_OVERLAPPEDWINDOWタスクバーを提案します
  • ExStyle & WS_EX_CLIENTEDGENOT_TASKBARを提案します
  • ExStyle & WS_EX_DLGMODALFRAMENOT_TASKBARを提案します

推測には他にもルールがあると思いますが、実際、Windowsのバージョンごとに推測ルー​​ルが変更されています。

于 2010-02-14T21:10:34.010 に答える
7
  1. トップレベル ウィンドウ

  2. WS_EX_APPWINDOW -> タスクバー、他のスタイルに関係なく!

  3. OWNER は NULL でなければなりません (GetWindow(window, GW_OWNER))

  4. いいえ: WS_EX_NOACTIVATE または WS_EX_TOOLWINDOW:

順序が重要です。

2 番目の質問: 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ではもう不可能です。したがって、すべてのトップレベル ウィンドウをループする必要があります。

于 2010-02-14T21:25:27.773 に答える
1

この MSDN の記事には、シェルがウィンドウのタスクバー ボタンを作成することを決定するタイミングと理由に関するいくつかの良い情報があります。

シェルは、アプリケーションが所有されていないウィンドウを作成するたびに、タスク バーにボタンを作成します。ウィンドウ ボタンがタスク バーに確実に配置されるようにするには、所有されていないウィンドウを WS_EX_APPWINDOW 拡張スタイルで作成します。ウィンドウ ボタンがタスク バーに配置されないようにするには、所有されていないウィンドウを WS_EX_TOOLWINDOW 拡張スタイルで作成します。別の方法として、非表示のウィンドウを作成し、この非表示のウィンドウを可視ウィンドウの所有者にすることができます。

于 2011-09-26T21:22:06.027 に答える