我正在寻找一种方法来检查给定的窗口是否有一个任务栏button。 也就是说,给定一个窗口句柄,如果窗口在任务栏中,我需要一个TRUE,否则就是FALSE。
相反,我想知道是否有办法得到属于给定任务栏button的窗口的句柄,我想这将需要一种方法来枚举通过任务栏button。
(第一个前者是我需要的部分,后一部分是可选的。)
非常感谢。
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 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的版本变成了Windows。
Toplevel窗口
WS_EX_APPWINDOW – >任务栏,不管其他样式!
OWNER必须为NULL(GetWindow(window,GW_OWNER))
否: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。 所以你需要遍历所有顶层窗口。
这篇MSDN文章有一些关于何时和为什么Shell决定为窗口创建一个任务栏按钮的好信息:
每当应用程序创建一个不属于的窗口时,Shell在任务栏上创建一个按钮。 要确保窗口按钮放置在任务栏上,请使用WS_EX_APPWINDOW扩展样式创建一个无主窗口。 要防止将窗口按钮放置在任务栏上,请使用WS_EX_TOOLWINDOW扩展样式创建无主窗口。 或者,您可以创建一个隐藏窗口,并将此隐藏窗口设置为可见窗口的所有者。