c - 未父窗口无法设置HMENU ID?

标签 c winapi

我有一个自定义窗口类(我用RegisterClassEx()创建的)。如果创建此类的窗口实例并设置其HMENU属性,CreateWindowEx()函数将失败。
为什么我不能设置这种窗口的id/HMENUid?

// hwnd = NULL
hwnd = CreateWindowEx(0, WND_CLASS_NAME.c_str(), wndTitle.c_str(), wndFlags,    
    wndDimensions.left, wndDimensions.top, wndDimensions.right, wndDimensions.bottom, 
    NULL, (HMENU)50001, hinstance, NULL);

// hwnd is valid
hwnd = CreateWindowEx(0, WND_CLASS_NAME.c_str(), wndTitle.c_str(), wndFlags,    
    wndDimensions.left, wndDimensions.top, wndDimensions.right, wndDimensions.bottom, 
    NULL, 0, hinstance, NULL);

整个目的是能够调用GetDlgCtrlId(hwnd);

最佳答案

这不起作用CreateWindowEx函数有点混乱,因为参数的解释不同,这取决于您创建的窗口类型您必须仔细阅读文档以避免做出错误的假设。
有重叠/弹出窗口(我认为以前在16位窗口中有区别,但这种区别不再相关;它们实际上是相同的)和子窗口。第一种是你凭直觉想到的,因为它们看起来像窗户。它们是应用程序用于其主窗口、对话框、浮动工具窗口等的类型。第二种类型是特定类型的窗口,只能用作另一个窗口的子窗口。控件是子窗口,如按钮、静态控件、列表视图等。子窗口由父窗口(它们总是有父窗口)承载,父窗口可以是另一个子窗口,也可以是重叠/弹出窗口。
只有子窗口具有应用程序定义的ID。使用CreateWindowEx样式标志调用WS_CHILD函数时指定此ID(该标志请求创建子窗口)。当该标志存在时,hMenu参数不会解释为菜单的句柄。相反,它被解释为子窗口的ID
当调用不带CreateWindowEx样式标志的WS_CHILD函数时(这意味着您传递的是WS_OVERLAPPEDWS_POPUP,我们已经看到这两者基本上是可以互换的),hMenu参数被解释为菜单的句柄。如果它是菜单的有效句柄,则此菜单与窗口关联。如果为空,则窗口使用类菜单(在创建窗口类期间调用RegisterClassEx时指定的菜单)
two fundamental types of windows试图在hMenu参数的描述中说明这一点。
上面写着:
华萌[英寸,可选]
类型:HMENU
菜单的句柄,或根据窗口样式指定子窗口标识符。对于重叠窗口或弹出窗口,humenu标识要与窗口一起使用的菜单;如果要使用类菜单,则可以为空。对于子窗口,hMenu指定子窗口标识符,一个整数值,对话框控件用来通知其父窗口事件。应用程序确定子窗口标识符;对于具有相同父窗口的所有子窗口,它必须是唯一的。
言外之意应该是显而易见的。窗口不能同时具有菜单和ID。它既有菜单(如果是重叠/弹出窗口)也有子窗口ID(如果是子窗口)。子窗口从来没有菜单这在技术上是不可能的,因为它们有id。因此,您要做的是不可能的:重叠/弹出窗口不能设置ID。
您在问题中声明您的意图是能够调用GetDlgCtrlID函数,但是The function's documentation非常清楚它只适用于子窗口。首先,函数的名字意味着它适用于控件(缩写为“ctrl”),根据定义,控件必须是子窗口。进一步阅读(斜体注释是我的):
GetDlgCtrlID接受子窗口句柄以及对话框中控件的句柄。[从技术上讲,这是不必要的区别。如我们所见,对话框中的控件是子窗口。但是,据推测,作者是特别注意尽可能清楚的。]应用程序在创建窗口时设置子窗口的标识符,方法是在调用CreateWindowCreateWindowEx函数时将标识符值分配给humenu参数。
尽管如果hwndCtl是顶级窗口的句柄,那么GetDlgCtrlID可能会返回一个值,但是顶级窗口(这意味着重叠窗口或弹出窗口)不能有标识符,并且这样的返回值永远无效。
特别注意最后一句。
当然,有一些方法可以识别重叠窗口和弹出窗口:它们的句柄。这是CreateWindowEx函数返回给您的值(假设成功),您可以将此句柄保存为窗口的ID。它保证在系统范围内是唯一的(尽管在您的窗口被破坏后,它可能会被另一个窗口重用),并且是标识窗口的最可靠的方法。
如果由于某种原因,您无法保存窗口句柄,但以后仍需要查找顶级窗口,则可以调用that function's documentation函数。这将使用窗口类名和窗口标题来查找匹配的窗口。如果找到匹配项,则返回窗口句柄。(再次注意顶层窗口和子窗口之间的区别。FindWindow不适用于子窗口。如果要搜索子窗口,则必须改为调用FindWindow。)
注意,创建子窗口后,可以通过分别将FindWindowEx索引传递给GWL_IDGetWindowLongPtr函数来设置或检索其ID。此索引仅对子窗口有意义,因为没有其他类型的窗口具有ID。
‡请注意,创建重叠/弹出窗口后,可以使用SetWindowLongPtr检索其菜单句柄或使用GetMenu设置其菜单句柄。同样,这些函数的文档被迫强调,子窗口不能有菜单。SetMenu在调用子窗口时失败,返回“未定义”结果;GetMenu同样失败,设置错误代码。

关于c - 未父窗口无法设置HMENU ID?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37505212/

相关文章:

c - 不需要的 printf 输出

c - 使用 Windows API 将无模式对话框作为子窗口嵌入

c - 选项卡控件上的闪烁 - WIN32

windows - 是否值得记住windows API "language"

C、对结构队列进行排序

c++ - 使用 GCC,我可以在每个函数的基础上禁用 -Wframe-larger-than 吗?

c - 结构和刷新(stdin)

C:分配结构体的二维数组

winapi - 为什么我的 PE 文件无效?

windows - 为什么 WOW64 进程上的 CreateEnvironmentBlock 会给我 PROCESSOR_ARCHITECTURE=AMD64