从 hWnd 获取(资源)ID

Posted

技术标签:

【中文标题】从 hWnd 获取(资源)ID【英文标题】:Get the (resource) ID from hWnd 【发布时间】:2012-07-19 21:23:25 【问题描述】:

在 ResourceHacker 中,当您打开可执行文件(Windows)时,您可以看到与对话框关联的标识符。有谁知道他们来自哪里?我的意思是,如何在我的 C++ 程序中执行相同的操作以从 HWND 获取 ID?

顺便说一句,GetWindowLong(hwnd, GWL_ID) 返回 0。

谢谢

【问题讨论】:

找出该 HWND 的可执行文件,并从中提取资源。呵呵。 @CatPlusPlus:如果该对话框是在运行时创建的,例如通过调用CreateDialogIndirect 怎么办?该对话框甚至没有资源 ID,因为模板是在内存中创建的。您将资源与活动对象混淆了。 【参考方案1】:

GetWindowLong(hwnd, GWL_ID) 返回对话框中控件的标识符,但不能用于对话框本身,因为对话框没有标识符。

与对话框相关联的标识符实际上用于引用资源 blob 本身,而不是窗口。它们用于创建对话框(请参阅CreateDialog()。

创建对话框后,与原始模板或该标识符没有任何联系。实际上,该 ID 没有用处,对话框仅由其HWND 标识。请注意,您可以使用相同的对话框资源创建多个不同的对话框。

这些标识符(通常)由资源编辑器按顺序分配,或者如果您手动创建资源,则手动分配。

有关该主题的更多信息,您可以阅读CreateDialogIndirect() 函数,该函数不使用资源创建对话框。

【讨论】:

【参考方案2】:

在这里您可以找到一个很好的答案: http://blogs.msdn.com/b/oldnewthing/archive/2005/07/08/436815.aspx

这就像在问,“给定一盘食物,我该如何恢复 食谱的原始食谱和页码?”通过做化学 分析食物,你也许可以恢复“一个”食谱,但是 食物本身并没有说:“我来自 烹饪,第 253 页。”

所以答案是微软没有提供获取对话框ID的方法。他们本可以轻松地将其存储在任何地方以使其可用,但他们没有。

但仍有办法做到这一点,尽管它不是防弹的。你可以:

1.) 通过GetWindowModuleFileName()获取对话框的创建者文件

2.) 通过 LoadLibraryEx(..., LOAD_LIBRARY_AS_IMAGE_RESOURCE) 加载此 Exe 或 Dll

3.) 通过 EnumResourceNames() 枚举 Exe 或 Dll 中的所有 RT_DIALOG 资源,其中对话框 ID 在名称中:ResourceName = MAKEINTRESOURCE(IDD_DIALOG_ID)

4.) 通过LoadResource()LockResource()CreateDialogIndirect() 不可见地创建每个枚举对话框,但不显示带有ShowWindow() 的对话框。

5.) 通过EnumChildWindows() 枚举每个对话框中的子控件并将它们与您的对话框进行比较。

6.) 释放所有句柄并销毁对话框。

在一个 Exe/Dll 文件中不太可能有两个相同的对话框。但问题是,在WM_INITDIALOG 中,程序员可能会消除(销毁)或添加或修改子控件。所以你的搜索算法必须是容错的。这可以通过计算资源中的每个对话与您的对话之间的一致性来实现。您可以计算有多少子控件 ID (GetDlgCtrlID()) 和类名 (GetClassName()) 匹配。 (例如 Class="BUTTON" 和 ID = 311")虽然程序员可以轻松更改控件的文本或移动它,但更改 ID 的可能性不大,并且没有多大意义,更改子控件的类甚至是不可能的。

正如我所说:这不是万无一失的,但您会发现最有可能用于创建对话框的资源的 ID。

请注意,并非所有对话框都来自 Microsoft 资源。 它们可以由使用自己的模板类型的 GUI 框架创建。在这种情况下,您将永远找不到对话框 ID,因为它根本不存在。

【讨论】:

正如您所说,该算法根本不是防弹的。可能需要考虑的其他事项:在运行时创建的控件,以及在运行时删除的控件。除此之外,这是一个很好的答案,有一个值得信赖的旧新事物的介绍性链接。绝对值得一票。

以上是关于从 hWnd 获取(资源)ID的主要内容,如果未能解决你的问题,请参考以下文章

获取调用程序/被调用程序的 HWND

从 C++ 中的可执行路径(或从 hWnd,或从 pid)获取程序名称

来自 CreateWindow/CreateDialog 的 HWND 可以从另一个线程获取消息吗?

如何从 hWnd 获取 Windows 10 应用商店应用程序的“应用程序名称”(例如 Edge)

获取 Excel InputBox 方法的 hwnd

知道一个窗体的句柄,如何获取这个窗体