要是去掉了窗口的标题栏怎么移动窗口呢?本文围绕此话题展开说明。
在创建窗口样式的时候传递WS_POPUP和WS_SYSMENU的组合就可以隐藏标题栏。
// Create Window
HWND hWnd = ::CreateWindowEx(NULL, szWindowClass, "Title",
WS_POPUP|WS_SYSMENU|WS_SIZEBOX, 100, 100, 300, 300, NULL, NULL, hInstance, NULL);
现在窗口就没办法移动了。也不能比较方便地关闭。下面就通过欺骗windows解决移动窗口的问题。
在windows下,没一个鼠标消息都是由WM_NCHITTEST消息产生的,这个消息的参数包含了鼠标位置的信息。通常是将这个消息让DefWindowProc函数处理,该返回值会返回一个值来告诉Windows鼠标按下的是窗口的那一部分。Windows利用这个返回值来决定要发送的鼠标信息的类型。如果用鼠标左键单击窗口的标题栏,处理WM_NCHITTEST消息的DefWindowProc函数会返回HTCAPTION,然后Windows会再向该窗口发送WM_NCLBUTTONDOWN消息。如果DefWindowProc函数的返回值是HTCLIENT,Windows就将鼠标所在位置的坐标从屏幕坐标转成客户区坐标,并通过WM_LBUTTONDOWN消息通知用户。
要想在客户区拖动鼠标就能移动窗口,必须骗下Windows,可以通过改变处理WM_NCHITTEST消息的DefWindowProc函数的返回值实现这个。
case WM_NCHITTEST:
{
UINT nHitTest;
nHitTest = ::DefWindowProc(hWnd, WM_NCHITTEST, wParam, lParam);
if (nHitTest == HTCLIENT &&
::GetAsyncKeyState(MK_LBUTTON) < 0) // 如果鼠标左键按下,GetAsyncKeyState函数的返回值小于0
nHitTest = HTCAPTION;
return nHitTest;
}
通过WM_NCHITTEST在DefWindowProc返回值来判断如果是在客户端点击HTCLIENT消息同时是左键就将返回值替换为点击标题栏(HTCAPTION消息)。这样就可以了
#include <windows.h>
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("欺骗Windows移动窗口");
HWND hwnd;
MSG msg;
WNDCLASSEX wndclassex = {0};
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = WndProc;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = hInstance;
wndclassex.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclassex.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclassex.lpszMenuName = NULL;
wndclassex.lpszClassName = szAppName;
wndclassex.hIconSm = wndclassex.hIcon;
if (!RegisterClassEx (&wndclassex))
{
MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx(NULL, szAppName, "Title",
WS_POPUP|WS_SYSMENU|WS_SIZEBOX, 100, 100, 300, 300, NULL, NULL, hInstance, NULL);
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE:
return (0);
case WM_NCHITTEST:
{
UINT nHitTest;
nHitTest = ::DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
if (nHitTest == HTCLIENT &&
::GetAsyncKeyState(MK_LBUTTON) < 0) // 如果鼠标左键按下,GetAsyncKeyState函数的返回值小于0
nHitTest = HTCAPTION;
return nHitTest;
}
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
TextOut (hdc, 0, 0, "A Window!", 27);
EndPaint (hwnd, &ps);
return (0);
case WM_DESTROY:
PostQuitMessage (0);
return (0);
}
return DefWindowProc (hwnd, message, wParam, lParam);
}