Reputation: 152
I'm asked to add new feature to an existing program. The program consists of a dialog without title/border. I need couple of things:
Here's what I found so far:
void MyDialog::onMessageReceived(UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_LBUTTONDOWN:
lastX=LOWORD(lParam);
lastY=HIWORD(lParam);
SendMessage(DlgHandle, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
break;
case WM_LBUTTONUP:
if (LOWORD(lParam)==lastX && HIWORD(lParam)==lastY)
onKillButtonClick();
break;
}}
EDIT: This function is called in this way:
INT_PTR CALLBACK MyDialog::dialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
_this->onMessageReceived(uMsg, wParam, lParam);
}
Moving the window works very well, but looks like the WM_LBUTTONUP event is lost. I had to click twice to get it fired. Hope someone can help me...
EDIT: Using Spy++ I saw that WM_LBTTONUP is fired, but immediately after a new WM_NCLBUTTONDOWN is emitted.
Upvotes: 1
Views: 431
Reputation: 11321
First, I agree with Michael Walz - this is a very confusing behavior: the processing of the mouse up event depends on whether or not it has moved... What if it moved just a little bit? I would much rather dismiss this dialog with a different action - click on the icon, right-click, etc.
However, the correct way to let the user move your captionless window is to process WM_NCHITTEST
message and return HTCAPTION
:
case WM_NCHITTEST:
SetWindowLong(hDlg, DWL_MSGRESULT, HTCAPTION);
return HTCAPTION;
Unfortunately, Windows then will take over all mouse events, so, as you observed, you would never get WM_LBUTTONUP
. You have an option to set a short timer and see if the user started to move your window; cancel it when you get WM_ENTERSIZEMOVE
message. If that timer fires - close your window. Yes, it's also awkward, but no more thatn your proposal.
Another way is to handle the move yourself:
static bool bDragging(false), bMoved(false);
static POINT pt1 = {}, pt2 = {};
static RECT r;
switch (message)
{
case WM_LBUTTONDOWN:
GetWindowRect(hDlg, &r);
pt1 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ClientToScreen(hDlg, &pt1);
bDragging = true;
bMoved = false;
break;
case WM_MOUSEMOVE:
if (bDragging)
{
pt2 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ClientToScreen(hDlg, &pt2);
if (pt2.x != pt1.x || pt2.y != pt1.y)
{
OffsetRect(&r, pt2.x - pt1.x, pt2.y - pt1.y);
SetWindowPos(hDlg, 0, r.left, r.top, 0, 0, SWP_NOSIZE);
pt1 = pt2;
bMoved = true;
}
}
break;
case WM_LBUTTONUP:
bDragging = false;
if (!bMoved)
PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0);
bMoved = false;
break;
}
return (INT_PTR)FALSE;
Upvotes: 1