Windows 为什么顶级窗口的GetParent(hwnd)和(hwnd)::GetWindow(hwnd,GW_OWNER)会给出不同的结果?
我一直在研究窗口层次结构是如何工作的,发现了一个不一致的地方。两个函数调用Windows 为什么顶级窗口的GetParent(hwnd)和(hwnd)::GetWindow(hwnd,GW_OWNER)会给出不同的结果?,windows,winapi,win32gui,Windows,Winapi,Win32gui,我一直在研究窗口层次结构是如何工作的,发现了一个不一致的地方。两个函数调用GetParent(hwnd)和(hwnd)::GetWindow(hwnd,GW_OWNER)返回的值大多数人都同意,但并不总是用于顶级窗口 我之所以假设这些是顶级窗口,是因为它们是使用函数找到的,函数仅用于枚举顶级窗口。还使用测试hWnd==get祖先(hWnd,GA_ROOT)进行了确认,如对的回答中所述 我在AVGUI.exe中的windowclass32770和explorer.exe中的windowclassC
GetParent(hwnd)
和(hwnd)::GetWindow(hwnd,GW_OWNER)
返回的值大多数人都同意,但并不总是用于顶级窗口
我之所以假设这些是顶级窗口,是因为它们是使用函数找到的,函数仅用于枚举顶级窗口。还使用测试hWnd==get祖先(hWnd,GA_ROOT)
进行了确认,如对的回答中所述
我在AVGUI.exe中的windowclass32770
和explorer.exe中的windowclassComboLBox
,notepad++.exe
,TeamViewer.exe
,privacyconclient.exe
,devenv.exe
。。。这一清单还在继续
GetParent(hwnd)
将返回GetDesktopWindow()
的hwnd
,但(hwnd)::GetWindow(hwnd,GW_OWNER)
将返回nullptr
。因此,如果GetParent()
应该返回顶级窗口的所有者,那么当(HWND)::GetWindow(HWND,GW_owner)
返回一个nullptr
时,它从何处获取
它确实同意(HWND)::GetWindowLongPtr(HWND,GWLP\u hwndpart)
,但这表明它是一个子窗口,这在某种程度上是有意义的,因为许多人的窗口类被列为ComboLBox
。然而,我见过其他的HWND,它们的值应该在哪里,这可能是因为基于上下文,该值被忽略了。另一个原因是这些窗口在某一点上可能是非顶级窗口,!(GetWindowLong(hwnd、GWL_样式)和WS_子级)
返回false
通过我所做的额外分析,似乎某些应用程序正在以某种方式将非顶级窗口升级为顶级窗口,这表明存在一些错误,或者正在使用一些未记录/未定义的行为,并导致奇怪的HWND链接
有人能确认这些是由bug引起的,或者是出于某种合法的原因正在做的事情吗
编辑
最小、完整且可验证的示例:
#include <AtlBase.h> // Conversion routines (CW2A)
#include <Windows.h> // Windows stuff
#include <assert.h>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <set>
#include <psapi.h>
#include <regex>
auto FIELD_SEPERATOR = L",";
auto& output_window_class_and_title(std::wostream & os, const HWND &hWnd)
{
wchar_t window_class[1024], window_title[1024];
window_class[0] = window_title[0] = 0;
::GetClassNameW(hWnd, window_class, _countof(window_class));
::GetWindowTextW(hWnd, window_title, _countof(window_title));
// replacing any CRLFs with field separators
auto wc
= std::regex_replace(window_class, std::wregex(L"(\r\n?|\n\r?)")
, L" " );
auto wt
= std::regex_replace(window_title, std::wregex(L"(\r\n?|\n\r?)")
, L" " );
os << CW2A(wc.c_str()) << FIELD_SEPERATOR << CW2A(wt.c_str());
return os;
}
// Store exe names
std::set<std::wstring> exe_names;
// Map pid to exe name
std::map<DWORD, std::wstring const*> pid_to_exe_name;
// Get exe name (from cache if possible)
const std::wstring * GetProcessName(DWORD pid)
{
const std::wstring * pProcess_name = nullptr;
auto it_found_pid = pid_to_exe_name.find(pid);
if (it_found_pid == pid_to_exe_name.end()) {
wchar_t exe_name[MAX_PATH]; exe_name[0] = 0;
if (HANDLE hProcess = ::OpenProcess(
PROCESS_ALL_ACCESS | PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, pid))
{
auto chars_copied = ::GetProcessImageFileNameW(hProcess, exe_name, _countof(exe_name));
assert(chars_copied > 0);
exe_name[chars_copied] = 0;
::CloseHandle(hProcess);
auto found = exe_names.emplace(exe_name);
pProcess_name = &*found.first;
}
else
{
auto found = exe_names.emplace(L"* Couldn't open process handle *");
pProcess_name = &*found.first;
}
pid_to_exe_name.try_emplace(pid, pProcess_name);
}
else {
pProcess_name = it_found_pid->second;
}
}
int main()
{
//auto* filename = "window-tree.txt";
//static std::wfstream os(filename, std::ios_base::out | std::ios_base::trunc);
static auto& os = std::wcout;
os.exceptions(os.badbit | os.failbit | os.eofbit);
os << std::hex;
try {
static HWND hDesktop = GetDesktopWindow();
EnumWindows([](_In_ HWND hwnd, _In_ LPARAM lParam) -> BOOL
{
assert(hwnd);
HWND hParent = ::GetParent(hwnd);
if (hParent == hDesktop) {
auto hOwner = (HWND)::GetWindow(hwnd, GW_OWNER);
auto hParent = (HWND)::GetWindowLongPtr(hwnd, GWLP_HWNDPARENT);
auto hParent_from_GetParent = ::GetParent(hwnd);
auto hParent_from_GetAncestor = ::GetAncestor(hwnd, GA_PARENT);
bool is_top_level = (hwnd == GetAncestor(hwnd, GA_ROOT));
bool is_top_level2 = !(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD);
DWORD pid;
auto tid = ::GetWindowThreadProcessId(hwnd, &pid);
std::wstring const* pProcess_name = GetProcessName(pid);
os
<< std::setw(8) << hwnd
<< FIELD_SEPERATOR << ::IsWindowVisible(hwnd)
<< FIELD_SEPERATOR << is_top_level
<< FIELD_SEPERATOR << is_top_level2
<< FIELD_SEPERATOR << std::setw(8) << hOwner
<< FIELD_SEPERATOR << std::setw(8) << hParent_from_GetParent
<< FIELD_SEPERATOR << std::setw(8) << hParent
<< FIELD_SEPERATOR << std::setw(8) << hParent_from_GetAncestor
<< FIELD_SEPERATOR << std::setw(4) << pid
<< FIELD_SEPERATOR << std::setw(4) << tid
<< FIELD_SEPERATOR << pProcess_name->c_str()
<< FIELD_SEPERATOR;
output_window_class_and_title(os, hwnd);
os
<< std::endl;
}
return TRUE;
}
, 0);
}
catch (std::ios_base::failure& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
有父窗口但没有所有者的窗口不是顶级窗口。这就是对您描述的场景的明显解释
更新
看起来情况并非如此,因为您现在解释了窗口来自EnumWindows
。文件上说:
EnumWindows函数不枚举子窗口,系统拥有的具有WS_子样式的少数顶级窗口除外
因此,我认为这些一定是你描述的窗户。这是系统拥有的顶级窗口,提供了WS_子样式 另请参见“家长和所有者窗口(审查)”一节(幻灯片28-33)。特别是幻灯片#31中有一张图表,显示了父母和所有者之间的区别。这是用猎枪回答的吗?由于该项是使用找到的,它必须是EnumWindows文档中的顶级窗口。它说“EnumWindows函数不枚举子窗口,系统拥有的少数具有WS_子样式的顶级窗口除外。”这些是窗口吗?他们是否有WS_子样式。还要注意,直到最近的编辑,问题才提到EnumWindows。我们不知道这些窗口把手是从哪里来的,也没有什么可以解释的。据我们所知,您正在根据问题标题调用GetWindowLongPtr。清理一下怎么样?GW\u OWNER
是GetWindow
函数的有效参数,而不是GetWindowLongPtr
函数。@JonathanPotter,谢谢。打字错误FixedDoe在我看来不像一个打字错误(标题仍然有那个“打字错误”)。如果您将GW_OWNER
(值4)传递给,它将只读取窗口额外数据中偏移量4处的值。对于未在该偏移量中分配额外数据的窗口,该值是不确定的。对于这样做的窗口,该值的含义对于窗口类实现是私有的。还不清楚,这个问题问的是什么。@I不清楚,错过了标题,谢谢。这是一个打字错误。你可以查我的密码。
000A0FF6,0,1,0,00000000,00010010,00000000,00010010,8520,6d44,\Device\HarddiskVolume2\Program Files (x86)\Notepad++\notepad++.exe,ComboLBox,
0094150C,0,1,0,00000000,00010010,00000000,00010010, 3ac,3f14,\Device\HarddiskVolume4\Windows\explorer.exe,ComboLBox,
0078181E,0,1,0,00000000,00010010,00000000,00010010,5e58,5068,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools\spyxx_amd64.exe,ComboLBox,
00FA16AA,0,1,0,00000000,00010010,00000000,00010010, 3ac,242c,\Device\HarddiskVolume4\Windows\explorer.exe,ComboLBox,
01121B00,0,1,0,00000000,00010010,00000000,00010010,4440,7b98,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
021304D0,0,1,0,00000000,00010010,00000000,00010010,5e1c,5b5c,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
011A11EE,0,1,0,00000000,00010010,00000000,00010010,5e1c,5b5c,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
018D1B7A,0,1,0,00000000,00010010,00000000,00010010,5e1c,5b5c,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
0137042A,0,1,0,00000000,00010010,00000000,00010010,5e1c,5b5c,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
0028065A,0,1,0,00000000,00010010,00000000,00010010,5e1c,5b5c,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
005B0472,0,1,0,00000000,00010010,00000000,00010010,8520,6d44,\Device\HarddiskVolume2\Program Files (x86)\Notepad++\notepad++.exe,ComboLBox,
00421248,0,1,0,00000000,00010010,00000000,00010010,8520,6d44,\Device\HarddiskVolume2\Program Files (x86)\Notepad++\notepad++.exe,ComboLBox,
00BA10F8,0,1,0,00000000,00010010,00000000,00010010,8520,6d44,\Device\HarddiskVolume2\Program Files (x86)\Notepad++\notepad++.exe,ComboLBox,
009E0EE2,0,1,0,00000000,00010010,00000000,00010010,8520,6d44,\Device\HarddiskVolume2\Program Files (x86)\Notepad++\notepad++.exe,ComboLBox,
00040822,0,1,0,00000000,00010010,00000000,00010010, 3ac,3d94,\Device\HarddiskVolume4\Windows\explorer.exe,ComboLBox,
000404A4,0,1,0,00000000,00010010,00000000,00010010, 7e0, 7dc,\Device\HarddiskVolume4\Program Files (x86)\Intel\Intel(R) Management Engine Components\IMSS\PrivacyIconClient.exe,ComboLBox,
000404A0,0,1,0,00000000,00010010,00000000,00010010, 7e0, 7dc,\Device\HarddiskVolume4\Program Files (x86)\Intel\Intel(R) Management Engine Components\IMSS\PrivacyIconClient.exe,ComboLBox,
000102FE,0,1,0,00000000,00010010,00000000,00010010,19dc, 4c4,\Device\HarddiskVolume2\Program Files (x86)\TeamViewer\TeamViewer.exe,ComboLBox,
00010290,0,1,0,00000000,00010010,00000000,00010010,19dc, 4c4,\Device\HarddiskVolume2\Program Files (x86)\TeamViewer\TeamViewer.exe,ComboLBox,
00EF16B4,0,1,0,00000000,00010010,00000000,00010010,4440,7b98,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
00840D20,0,1,0,00000000,00010010,00000000,00010010,4440,7b98,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
016A0E64,0,1,0,00000000,00010010,00000000,00010010,4440,7b98,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,
021B11F2,0,1,0,00000000,00010010,00000000,00010010,4440,7b98,\Device\HarddiskVolume4\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe,ComboLBox,