SetParent是Windows提供的设置窗口父窗体的API,函数原型比较简单:

1
2
3
4
HWND SetParent(
[in] HWND hWndChild,
[in, optional] HWND hWndNewParent
);

我们通常的使用方法是:

1
2
3
if(!SetParent(hChild, hParent)) {
// Failed
}

这种使用方法在大多情况下不会失败,但有时却会失败。究其原因,其在微软官方文档中已有说明SetParent Doc

由于兼容性问题,SetParent函数不会修改hWndChild窗口的WS_CHILDWS_POPUP样式,因此:

  • 如果hWndNewParent为NULL,你需要在调用SetParent函数清除WS_CHILD并设置WS_POPUP样式。
  • 如果hWndNewParent不为NULL并且hWndChild之前是桌面的子窗口,你需要在调用SetParent函数清除WS_POPUP并设置WS_CHILD样式。

总结上述原因,SetParent的正确使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool SetWinParent(HWND hChild, HWND hNewParent) {
HWND hOldParent = NULL;
if (hNewParent) {
LONG newStyle = GetWindowLong(hChild, GWL_STYLE);

newStyle &= ~WS_POPUP;
newStyle |= WS_CHILD;

SetWindowLong(hChild, GWL_STYLE, newStyle);

hOldParent = ::SetParent(hChild, hNewParent);
}
else {
hOldParent = ::SetParent(hChild, hNewParent);

LONG newStyle = GetWindowLong(hChild, GWL_STYLE);

newStyle &= ~WS_CHILD;
newStyle |= WS_POPUP;

SetWindowLong(hChild, GWL_STYLE, newStyle);
}
return !!hOldParent;
}