Click to See Complete Forum and Search --> : Problems with WM_NCHITTEST


Neandertal
June 16th, 2009, 05:32 PM
Hello mighty gurus.

I have an issue with WM_NCHITTEST notification and I hope someone here can help with this little problem.

So basically I'm creating messenger system using VC++ (6.0) and WinAPI. NO MFC AT ALL. In order to create custom skins for popup messages (those in the right bottom corners) Im creating totally flat empty window and draw an image backgroud on it (that part is not implemented yet).
The function to create notification message is similar to this one:

int notify(char *message, char *title, char *link, char *bgImage, HWND hPWnd)
{
static HWND hwndClient;

// Data validation

int Style = WS_CAPTION;

hwndClient = CreateWindow (szPopupNotifier, // window class name
TEXT (title), // window caption
Style, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
hPWnd, // parent window handle - main hidden window
NULL, // window menu handle
hInst, // program instance handle
NULL); // creation parameters
if (hwndClient)
{
SetWindowLong(hwndClient, GWL_STYLE, GetWindowLong(hwndClient, GWL_STYLE) & ~ WS_CAPTION);
// Calculate initial position on the screen and show the window.

return 0;
}

return 1;
}

As you can see after doing SetWindowLong the window is actually white rectangle.

WM_PAINT message of the window procedure has the code to draw black thin border of the window:

// Get window rectangle/size
GetClientRect(hwnd, &rect);

// Create brush to draw
HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));

// Draw frame
FrameRect(hdc, &rect, hBrush);

Also WM_PAINT draws the title bar and the close button - something like this [x].

Now here is the part where issue is starting to come out.

If the message is 2 long I only print the part of it in the little notifier window and that part has a link to open another bigger window
(dialog box) with the entire message. In the case of the short message with the link I implemented that WM_NCHITTEST to track notifications
WM_MOUSELEAVE and WM_MOUSEHOVER (to underline the message when user hovers it).

The code is similar to this one:
case WM_NCHITTEST:
hittest = DefWindowProc(hwnd, message, wParam, lParam);
if(HTCLIENT == hittest)
{
if(!inside)
{
inside = TRUE; // mouse pointer is inside
tme.cbSize = sizeof(TRACKMOUSEEVENT); // create tracking structure
tme.dwFlags = TME_HOVER | TME_LEAVE; // track WM_MOUSEHOVER & WM_MOUSELEAVE
tme.hwndTrack = hwnd; // track in this window
tme.dwHoverTime = 25; // tracking time
TrackMouseEvent(&tme); // set tracking
}
}
return hittest;

case WM_MOUSELEAVE:
if (link != NULL)
{
inside = MouseOverNotif = FALSE;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;

case WM_MOUSEHOVER:
if (link != NULL)
{
inside = MouseOverNotif = TRUE;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;

Also application has to know if user wants to see entire message or close the notifier popup. So WM_LBUTTONDOWN has the following code:
case WM_LBUTTONDOWN:
GetClientRect(hwnd, &rect);

mousePosX = LOWORD(lParam);
mousePosY = HIWORD(lParam);

if (mousePosX >= rect.right - 18 && mousePosX <= rect.right - 3
&& mousePosY >= 6 && mousePosY <= 19)
{
//SendMessage(hwnd, WM_CLOSE, 0, 0);
DestroyWindow(hwnd);
hwnd = NULL;
}
else if (link != NULL)
{
// Open or refresh dialog box with entire message
}

return 0;

Here hwndClient from notify is equal to hwnd from win proc but that's ok since I don't display more than one notifier popup at a time.

To move the window I have a timer within that notifier popup. If the message was displayed (means it was pulled up and down) I kill the timer from
the timer itself and call 'DestroyWindow(hwnd); hwnd = NULL;' again.

The issue is very simple. If the user click on the customer [x] button the next message popup don't receive WM_NCHITTEST notification and
WM_MOUSELEAVE & WM_MOUSEHOVER are never registered :(.

Ive tried to use WM_MOUSEMOVE instead of WM_NCHITTEST but the result is the same. After closing the popup from custom [x] button that WM_MOUSEMOVE
is not tracked either.

The 'notify' function is invoked from the main (hidden) window. Messages are read from one thread and displayed from another one.
If you need more data or source code to take a look at please make me know.

Appreciate any help or advice.

Thanx in advance.

olivthill2
June 17th, 2009, 05:17 PM
Maybe messages are not transmitted because you have:case WM_MOUSEHOVER:
...
return 0;
Perhaps, I am not sure, it would be better to have:case WM_MOUSEHOVER:
...
return(DefWindowProc(hwnd, msg, wParam, lParam));
Besides, I don't know if this is really useful to invent a new type of window, when there are already plenty of them. Personally, I like using the type of window that was originally designed for floating tools, but which can be used for many other purposes:hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, // small caption ...

BTW, please, put your lines of code between and .

Neandertal
June 18th, 2009, 02:05 PM
The problem starts in WM_NCHITTEST notification. WM_NCHITTEST tells the application to track other 2 notifications and after clicking on customized [x] button that notification is never received. However I already tried returning DefWindowProc from that WM_MOUSEHOVER and the issue is still there. According to MSDN website TrackMouseEvent also should be invoked from WM_MOUSEHOVER to keep tracking on but it works without that part anyway. Once again until user choosed to close the window :(.

Little fix I made (and it worked) was to change close code under WM_LBUTTONDOWN notification. Now I just pull down the window very fast and let timer close the window.

Yeah there are bunch of window styles available though sometimes its better to make your own style to control it all :D

Thanx for reply.