LRESULT CALLBACK CWindowWnd::__ControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowWnd
*
pThis
=
NULL;
if
( uMsg
==
WM_NCCREATE )
{
LPCREATESTRUCT lpcs
=
reinterpret_cast
<
LPCREATESTRUCT
>
(lParam);
pThis
=
static_cast
<
CWindowWnd
*>
(lpcs
->
lpCreateParams);
pThis
->
m_hWnd
=
hWnd;
::SetProp(hWnd,
"
WndX
"
, (HANDLE) pThis);
}
else
{
pThis
=
reinterpret_cast
<
CWindowWnd
*>
(::GetProp(hWnd,
"
WndX
"
));
if
( uMsg
==
WM_NCDESTROY
&&
pThis
!=
NULL )
{
LRESULT lRes
=
::CallWindowProc(pThis
->
m_OldWndProc, hWnd, uMsg, wParam, lParam);
::SetProp(hWnd,
"
WndX
"
, NULL);
if
( pThis
->
m_bSubclassed ) pThis
->
Unsubclass();
pThis
->
m_hWnd
=
NULL;
pThis
->
OnFinalMessage(hWnd);
return
lRes;
}
}
if
( pThis
!=
NULL )
{
return
pThis
->
HandleMessage(uMsg, wParam, lParam);
}
else
{
return
::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowWnd
*
pThis
=
NULL;
if
( uMsg
==
WM_NCCREATE )
{
LPCREATESTRUCT lpcs
=
reinterpret_cast
<
LPCREATESTRUCT
>
(lParam);
pThis
=
static_cast
<
CWindowWnd
*>
(lpcs
->
lpCreateParams);
pThis
->
m_hWnd
=
hWnd;
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast
<
LPARAM
>
(pThis));
}
else
{
pThis
=
reinterpret_cast
<
CWindowWnd
*>
(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
if
( uMsg
==
WM_NCDESTROY
&&
pThis
!=
NULL )
{
LRESULT lRes
=
::CallWindowProc(pThis
->
m_OldWndProc, hWnd, uMsg, wParam, lParam);
::SetWindowLongPtr(pThis
->
m_hWnd, GWLP_USERDATA,
0L
);
if
( pThis
->
m_bSubclassed ) pThis
->
Unsubclass();
pThis
->
m_hWnd
=
NULL;
pThis
->
OnFinalMessage(hWnd);
return
lRes;
}
}
if
( pThis
!=
NULL )
{
return
pThis
->
HandleMessage(uMsg, wParam, lParam);
}
else
{
return
::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
当 CreateWindow 采用已存在的类时,使用的是 __ControlProc, 位于 RegisterSuperclass()
wc.lpfnWndProc = CWindowWnd::__ControlProc;
当 CreateWindow 采用创建的类时,使用的是 __WndProc, 位于 RegisterWindowClass()
wc.lpfnWndProc = CWindowWnd::__WndProc;
这两个函数唯一不同的是,
__ControlProc 使用 SetProp() 的方式来设置 This 指针, 而
__WndProc 使用 SetWindowLogPtr -> GWLP_USERDATA 的方式来设置 This 指针
·使用已存在的类时,或许是怕别人已经设置过 GWLP_USERDATA ,所以这里采用了 SetProp() 的方式
void
CWindowWnd::CenterWindow()
{
ASSERT(::IsWindow(m_hWnd));
ASSERT((GetWindowStyle(m_hWnd)
&
WS_CHILD)
==
0
);
RECT rcDlg
=
{
0
};
::GetWindowRect(m_hWnd,
&
rcDlg);
RECT rcArea
=
{
0
};
RECT rcCenter
=
{
0
};
HWND hWndParent
=
::GetParent(m_hWnd);
HWND hWndCenter
=
::GetWindowOwner(m_hWnd);
::SystemParametersInfo(SPI_GETWORKAREA, NULL,
&
rcArea, NULL);
if
( hWndCenter
==
NULL ) rcCenter
=
rcArea;
else
::GetWindowRect(hWndCenter,
&
rcCenter);
int
DlgWidth
=
rcDlg.right
-
rcDlg.left;
int
DlgHeight
=
rcDlg.bottom
-
rcDlg.top;
//
Find dialog's upper left based on rcCenter
int
xLeft
=
(rcCenter.left
+
rcCenter.right)
/
2
-
DlgWidth
/
2
;
int
yTop
=
(rcCenter.top
+
rcCenter.bottom)
/
2
-
DlgHeight
/
2
;
//
The dialog is outside the screen, move it inside
if
( xLeft
<
rcArea.left )
xLeft
=
rcArea.left;
else
if
( xLeft
+
DlgWidth
>
rcArea.right )
xLeft
=
rcArea.right
-
DlgWidth;
if
( yTop
<
rcArea.top )
yTop
=
rcArea.top;
else
if
( yTop
+
DlgHeight
>
rcArea.bottom )
yTop
=
rcArea.bottom
-
DlgHeight;
::SetWindowPos(m_hWnd, NULL, xLeft, yTop,
-
1
,
-
1
, SWP_NOSIZE
|
SWP_NOZORDER
|
SWP_NOACTIVATE);
}
·一直以为有 CenterWindow() 这个API……,看来是因为MFC用久的缘故罢
HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
{
if( GetSuperClassName() != NULL && !RegisterSuperclass() )
return NULL;
if( GetSuperClassName() == NULL && !RegisterWindowClass() )
return NULL;
m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI::GetResourceInstance(), this);
ASSERT(m_hWnd!=NULL);
return m_hWnd;
}
这里在 lpParam 参数将 this 指针传过去,在 WM_NCCREATE 消息中再获取 this 指令,但MSDN 相关解释却是在 WM_CREATE 消息处理……
lpParam[in] Pointer to a value to be passed to the window through the CREATESTRUCT structure (lpCreateParams member) pointed to by the lParam param of the WM_CREATE message. This message is sent to the created window by this function before it returns.
If an application calls CreateWindow to create a MDI client window, lpParam should point to a CLIENTCREATESTRUCT structure. If an MDI client window calls CreateWindow to create an MDI child window, lpParam should point to a MDICREATESTRUCT structure. lpParam may be NULL if no additional data is needed.
void CWindowWnd::ResizeClient(int cx /*= -1*/, int cy /*= -1*/)
{
ASSERT(::IsWindow(m_hWnd));
RECT rc = { 0 };;
if( !::GetClientRect(m_hWnd, &rc) )
return;
if( cx != -1 ) rc.right = cx;
if( cy != -1 ) rc.bottom = cy;
if( !::AdjustWindowRectEx(&rc, GetWindowStyle(m_hWnd), (!(GetWindowStyle(m_hWnd) & WS_CHILD) && (::GetMenu(m_hWnd) != NULL)), GetWindowExStyle(m_hWnd)) )
return;
UINT uFlags = SWP_NOZORDER | SWP_NOMOVE;
::SetWindowPos(m_hWnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, uFlags);
}
AdjustWindowRectEx()
函数功能:该函数依据所需客户矩形大小,计算需要的窗口矩形的大小。计算出的窗口矩形随后可以传送给CreateWindowEx函数,用于创建一个客户区所需大小的窗口。
函数原型:BOOL AdjustWindowRectEX(LPRECT lpRect,DWORD dwStyte;BOOL bMenu;DWORD dwExStyle);
参数:
lpRect:指向RECT结构的指针,该结构包含所需客户区域的左上角和右下角的坐标。函数返回时,该结构包含容纳所需客户区域的窗口的左上角和右下角的坐标。
dwStyle:指定将被计算尺寸的窗口的窗口风格。
bMenu:指示窗口是否有菜单。
dwExStyle:指定将被计算尺寸的窗口的扩展窗口风格。
返回值:如果函数成功,返回值为非零;如果函数失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。
备注:客户矩形是指完全包含一个客户区域的最小矩形;窗口矩形是指完全包含一个窗口的最小矩形,该窗口包含客户区与非客户区。
当一个菜单条下拉出两行或更多行时,AdjustWindowRect函数不增加额外的空间。
速查:Windows NT:3.1以上版本;Windows:95以上版本;Windows CE:1.0以上版本;头文件:winuser.h;库文件:user32.lib。