SetWindowLongPtrGWL_HWNDPARENT和SetParent有什么区别?

问题描述

我需要为桌面上的某些应用程序窗口创建一个水印窗口(markHwnd),水印窗口样式为:

            uint dwStyle = Win32API.WS_CLIPSIBLINGS |
                          Win32API.WS_CLIPCHILDREN |
                          Win32API.WS_POPUP;
            uint dwExStyle = Win32API.WS_EX_layered |
                            Win32API.WS_EX_TRANSPARENT |
                            Win32API.WS_EX_NOACTIVATE |
                            Win32API.WS_EX_nopARENTNOTIFY |
                            Win32API.WS_EX_TOOLWINDOW;
            markHwnd = Win32API.CreateWindowEx(dwExStyle,wndclassRegResult,ti.ToString(),dwStyle,IntPtr.Zero,wndclasshInstance,IntPtr.Zero);

然后将其设置为应用程序窗口(targetHwnd)的自有窗口,有两种选择:

  • SetwindowLongPtr(markHwnd,(int)Win32API.GWL.GWL_HWNDPARENT, targetHwnd);
  • SetParent(markHwnd,targetHwnd);

建议哪个?

解决方法

SetWindowLongPtr()文档说:

请勿使用GWLP_HWNDPARENT索引调用SetWindowLongPtr来更改子窗口的父窗口。而是使用SetParent函数。

该文档所隐含的是GWLP_HWNDPARENT实际上更改了顶层窗口的所有者,而不是子窗口的 parent 。根据雷蒙德·陈(Raymond Chen)的说法:

https://devblogs.microsoft.com/oldnewthing/20100315-00/?p=14613

现在,一个窗口可以有一个父窗口,也可以有一个所有者,或者既没有窗口又没有窗口,但是永远不能拥有两者。

然后他继续说明CreateWindow/Ex()如何根据新窗口是否具有WS_CHILD样式来分配所有者和父母。

SetParent()文档说:

出于兼容性原因,SetParent不会修改其父级正在更改的窗口的WS_CHILD或WS_POPUP窗口样式。

因此,SetWindowLongPtr(GWLP_HWNDPARENT)用于更改顶级窗口的所有者,而SetParent()用于更改子窗口的父级。