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.
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.