[Win32API] WM_LBUTTONDOWN not workin

ok so I have main dialog with 5 tabs (child dialogs) and I want to capture left mouse click in first tab (TabOneDlgProc/IDD_ONE), however the wndproc is not even processing lbuttondown in my case, I've tried it in main window and it's working (when I click to main window, so somewhere outside the tab dialog), everything else related to tab one dialog is workign fine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
TAB_ONE DIALOGEX 1, 13, 335, 220
STYLE DS_SETFONT | WS_VISIBLE | WS_CHILDWINDOW
FONT 8, "Ms Shell Dlg", 0, 0, 1
{
    EDITTEXT        IDC_HERONAME, 11, 31, 64, 14, ES_AUTOHSCROLL
    LTEXT           "Hero Name", IDC_STATIC, 11, 22, 37, 8, SS_LEFT
    COMBOBOX        IDC_FACTION, 11, 55, 64, 30, CBS_DROPDOWNLIST | CBS_HASSTRINGS
    LTEXT           "Faction", IDC_STATIC, 11, 46, 24, 8, SS_LEFT
    EDITTEXT        IDC_DIFFICULTY, 85, 55, 64, 14, ES_AUTOHSCROLL | ES_NUMBER
    LTEXT           "Category", IDC_STATIC, 85, 22, 29, 8, SS_LEFT
    LTEXT           "Difficulty", IDC_STATIC, 85, 46, 28, 8, SS_LEFT
    COMBOBOX        IDC_CATEGORY, 85, 31, 64, 30, CBS_DROPDOWNLIST | CBS_HASSTRINGS
    PUSHBUTTON      "Sounds", IDC_BSOUNDS, 18, 77, 50, 14
    PUSHBUTTON      "Effects", IDC_BEFFECTS, 92, 70, 50, 14
    PUSHBUTTON      "Models", IDC_BMODELS, 92, 85, 50, 14
    LISTBOX         IDC_LRITEMS, 11, 133, 138, 57, WS_TABSTOP | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_SORT | LBS_NOTIFY
    LTEXT           "Recommended Items", IDC_STATIC, 11, 124, 68, 8, SS_LEFT
    PUSHBUTTON      "+", IDC_BRIA, 128, 191, 21, 14
    PUSHBUTTON      "-", IDC_BRIR, 106, 191, 21, 14
    LTEXT           "Strength: 0 (+0)", IDC_SSTR, 264, 50, 70, 8, SS_LEFT | SS_NOTIFY
    LTEXT           "Agility: 0 (+0)", IDC_SAGI, 264, 59, 70, 8, SS_LEFT | SS_NOTIFY
    LTEXT           "Intellect: 0 (+0)", IDC_SINT, 264, 68, 70, 8, SS_LEFT | SS_NOTIFY
    LTEXT           "Armor: 0 / 0", IDC_SARMOR, 264, 86, 70, 8, SS_LEFT | SS_NOTIFY
    LTEXT           "Mov. Speed: 0", IDC_SMOVESPEED, 264, 95, 70, 8, SS_LEFT | SS_NOTIFY
    COMBOBOX        IDC_PRIMATT, 264, 31, 52, 30, CBS_DROPDOWNLIST | CBS_HASSTRINGS
    CONTROL         "", IDC_HEROIMAGE, WC_STATIC, SS_BITMAP | SS_NOTIFY, 170, 27, 20, 20
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
BOOL CALLBACK MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case MY_WM_INITDIALOG:
		{
			ShowWindow(hTabs[0], TRUE);
			iCTab = 0;
			break;
		}
	case WM_SIZE:
		{
			OnSize(hTab, lParam);
			break;
		}
	case WM_NOTIFY:
		{
			LPNMHDR lpnmhdr = (LPNMHDR)lParam;

			if(lpnmhdr -> code == TCN_SELCHANGE)
			{
				int iTabItem = TabCtrl_GetCurSel(hTab);
				
				ShowTab(iTabItem);
			}
			break;
		}
	case WM_CREATE:
		{
			PostMessage(hWnd, MY_WM_INITDIALOG, 0, 0);
			break;
		}
	case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
			break;
		}
	case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
			}
			break;
		}
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

int TabControlInit(HWND hwndParent) 
{
	INITCOMMONCONTROLSEX icex;
	icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC = ICC_TAB_CLASSES;
	InitCommonControlsEx(&icex);
	
	RECT rcClient;
	GetClientRect(hwndParent, &rcClient);

	if (hTab == NULL)
		return 0;

	if (!SetWindowPos(hTab, HWND_TOP, 0, 0, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW))
		return 0;

	SetDefaultFont(hTab);
	
	TCITEM tie;
	tie.mask = TCIF_TEXT;
 
	for (int i = 0; i < 5; i++) 
	{
		tie.pszText = TabName[i];
		if (TabCtrl_InsertItem(hTab, i, &tie) == -1) 
		{
			DestroyWindow(hTab);
			return 0;
		}
	}
	RECT rcTab;
	TabCtrl_GetItemRect(hTab, 0, &rcTab);
	hTabs[0] = CreateDialog(g_hInst, MAKEINTRESOURCE(TAB_ONE), hTab, TabOneDlgProc);
	if (!SetWindowPos(hTabs[0], HWND_TOP, rcClient.left+1, rcClient.top+21, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW))
		return 0;
	hTabs[1] = CreateDialog(g_hInst, MAKEINTRESOURCE(TAB_TWO), hTab, TabTwoDlgProc);
	if (!SetWindowPos(hTabs[1], HWND_TOP, rcClient.left+1, rcClient.top+21, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW))
		return 0;
	hTabs[2] = CreateDialog(g_hInst, MAKEINTRESOURCE(TAB_THREE), hTab, TabThreeDlgProc);
	if (!SetWindowPos(hTabs[2], HWND_TOP, rcClient.left+1, rcClient.top+21, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW))
		return 0;
	hTabs[3] = CreateDialog(g_hInst, MAKEINTRESOURCE(TAB_FOUR), hTab, TabFourDlgProc);
	if (!SetWindowPos(hTabs[3], HWND_TOP, rcClient.left+1, rcClient.top+21, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW))
		return 0;
	hTabs[4] = CreateDialog(g_hInst, MAKEINTRESOURCE(TAB_FIVE), hTab, TabFiveDlgProc);
	if (!SetWindowPos(hTabs[4], HWND_TOP, rcClient.left+1, rcClient.top+21, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW))
		return 0;
	for(int a = 0; a < TAB_SLOT; a++)
	{
		ShowWindow(hTabs[a], FALSE);
	}
	return 1;
}

void ShowTab(int a)
{
	ShowWindow(hTabs[iCTab], FALSE);
	ShowWindow(hTabs[a], TRUE);
	iCTab = a;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
BOOL CALLBACK TabOneDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	switch(msg)
	{
	case WM_INITDIALOG:
		{
			for(int i = 0; i < 2; i++)
				SendMessage(GetDlgItem(hWnd, IDC_FACTION), CB_ADDSTRING, NULL, (LPARAM)Faction[i].c_str());
			SendMessage(GetDlgItem(hWnd, IDC_FACTION), CB_SETCURSEL, (WPARAM)0, NULL);
			for(int i = 0; i < 3; i++)
				SendMessage(GetDlgItem(hWnd, IDC_PRIMATT), CB_ADDSTRING, NULL, (LPARAM)PAtt[i]);
			SendMessage(GetDlgItem(hWnd, IDC_PRIMATT), CB_SETCURSEL, (WPARAM)0, NULL);
			HANDLE hBitmap = LoadImage(g_hInst, MAKEINTRESOURCE(IDB_DEFAULT), IMAGE_BITMAP, 128, 128, NULL);
			SendMessage(GetDlgItem(hWnd, IDC_HEROIMAGE), STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
			break;
		}
	case WM_LBUTTONDOWN:
		{
			MessageBox(hWnd, "LBD", "LBD", MB_ICONINFORMATION);
			break;
		}
	case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
				break;
			}
			switch(HIWORD(wParam))
			{
			case STN_CLICKED:
				{
					//stuff when clicking on static control, working fine
				}
			}
		}
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}
Last edited on
someone?
I think the problem is that your DialogProc -- TabOneDlgProc -- is calling DefWindowProc. With a DialogProc you should just return TRUE if you handle a message, or FALSE it you don't. You should not call DefWindowProc.

From the MSDN entry "DialogProc call back function"

Although the dialog box procedure is similar to a window procedure, it must not call the DefWindowProc function to process unwanted messages.

By returning to DefWindowProc you are probably disrupting the dialog manager's own message handling.

Andy

PS I also assume that you're adding a set of tabs to part of a window, rather than the whole of it. If it's the latter case, you should check out the PropertySheet function.
Last edited on
yup returning false works fine, also Ididn't really understand propertysheet, what does it do? how can it be used? only function of the function is not gonna help me (msdn)
PropertySheet() creates a set of PropertyPages, which are basically the same as your child dialogs. in one go, and handles the tabs, etc. for you. That is, it's a tabbed dialog.

A lot of apps use a property sheet for their options, inc. Outlook and Word.

Property Sheet (Windows)
http://msdn.microsoft.com/en-us/library/windows/desktop/bb774540%28v=vs.85%29.aspx
and in what aspects is propertysheet better than dialogs? since with dialogs I can handle their messages with wndproc, which is good so I can customize app better and also it's easier to find errors and code it etc since I have wndproc for each tab :P
Depends on what you want to do.

Property sheets are better when you want to create an multi-tabbed options dialog or a wizard. They do a bit of the work for you, cf. custom dialogs.

The (embedded) dialog approach allows you to customise more.

Note that each property page has its own dialogproc. Plus you can provide a callback function for the whole property sheet.

Andy
thanks, but I'll just stick to my dialogs for now :P

anyway, R/LBUTTONDOWN is not working when I click on any control (except edit, this one has its own menu that appears), how do I fix this? also is there any way to change the menu of edit control or do I have to subclass it?

edit: also how do I get ID of control my mouse is currently at? I've found only "GetCapture" but it's returning 0 when I click on my tab dialog (real ID is 102)

1
2
3
4
5
6
7
	case WM_RBUTTONDOWN:
		{
			char tmp[32];
			wsprintf(tmp, "%d", GetCapture());
			MessageBox(hWnd, tmp, tmp, NULL);
			break;
		}
Last edited on
(I think the main reason PropertySheet was introduced was to make it easier to code tabbed dialogs with a consistent look. Not sure it's easier overall.)

#1 WM_LBUTTONDOWN works for me with static controls (I based my code on that which you posted, assuming that that MainDlgProc was the app's main (dialog) window). But not for buttons, combo boxes, etc. This will require subclassing, which could be tricky to do for some controls (e.g. the combo box) without upsetting the normal behaviour (see GetComboBoxInfo)

#2 For the Edit control context menu, yes, you've got to subclass it.

#3 GetCapture tells you who's captured the mouse. i.e. the window which called SetCapture()

#4 To find out if a point is on a control you can:

1. Call ChildWindowFromPoint to get the handle of the window whose rect contains the point. Then compare the handle returned against the handles of the various controls.

2. Get the client rect of each control (GetClientRect), map it to the parent windows coordinates (MapWindowPoints), and then hittest it (PtInRect).

In both cases, if you want to test your static controls you'll have to give them all a unique ID, rather than just use IDC_STATIC.

Andy

PS Is WM_CONTEXTMENU worth looking at?
Last edited on
#1 when I use WM_RBUTTONDOWN in MainDlgProc (I use this dialog only to handle tabs and tab dialogs, the other things are in TabOneDlgProc and other TabDialogs) it works only when I click on main dlg area (screen below)

when I use it in TabOneDlgProc it works only if I click to blank area (clicking on static or any other control does nothing, I have SS_NOTIFY enabled (I use LBUTTON (WM_NOTIFT or how's that message called) to create another dialogs to change stuff, I want to use RBUTTON to change settings of those stats (str, int, agi, hero image etc))

using WM_CONTEXTMENU works on everything except edit control (yes even on buttons)

http://filebeam.com/8e493ce70c40520c63399cbb0e6f634c.jpg

#2 how exactly does subclassing works? I know what it does, but how does the proc works? will something like this work (this is not actual code, just something I think of that it works like) // subclassing editcontrol and own menu

1
2
3
4
5
6
7
8
9
10
BOOL CALLBACK EditControlProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
		case WM_CONTEXTMENU:
		{
			//stuff to bring up my menu and something to stop default menu, or I don't have to stop default menu?
		}
	}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
	case WM_CONTEXTMENU:
		{
			POINT p;
			p.x = LOWORD(lParam);
			p.y = HIWORD(lParam);
			HWND hwin = ChildWindowFromPoint(hWnd, p);
			if(hwin == GetDlgItem(hWnd, IDC_HEROIMAGE))
				MessageBox(hWnd, NULL, NULL, NULL);

			switch(wParam)
			{
				case IDC_HEROIMAGE:
				{
					MessageBox(hWnd, NULL, NULL, NULL);
					break;
				}
			}
			break;
		}


none of them is working, did I do something wrong? // I tried HIWORD and LOWORD with wParam to get IDC_HEROIMAGE, same result... but when I have only WM_CONTEXTMENU and I click on static control it works and brings message box
Last edited on
#1 The behaviour you describe makes sense to me, with the exception of the static controls. That works for me.

The WM_RBUTTONDOWN and WM_LBUTTONDOWN message are generated in TabOneDlgProc when I click on a static control (and I've added a hittest using ChildWindowFromPoint to confirm I've clicked in the right place).

If you want MainDlgProc to handle all the (e.g.) WM_RBUTTONDOWN, then get TabOneDlgProc to relay the message to MainDlgProc using SendMessage.

#2 The catch with WM_CONTEXTMENU is that the point it gives you is in scren coordinates, so you've got to convert it to client coords before you hittest (with ScreenToClient function).

#3 I don't see you doing the actual subclassing. Are you calling SetWindowLongPtr with GWLP_WNDPROC to set the new WndProc? And then using GWLP_WNDPROC to call on to the old WndProc from the subclass proc?

Andy
A stripped down test for subclassing.

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// main.cpp

#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <tchar.h>

#include "resource.h"

#define MY_WM_INITDIALOG  (WM_USER + 1)

TCHAR g_achTitle[] = _T("Subclass Test");
TCHAR g_achWindowClass[] = _T("Subclass_Test_WndClass");

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

LRESULT CALLBACK SubclassedEdit_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

WNDPROC g_pfnOldEditWndProc = NULL;

int APIENTRY
_tWinMain( HINSTANCE hInstance
         , HINSTANCE /*hPrevInstance*/
         , LPTSTR    /*lpCmdLine*/
         , int       nCmdShow     )
{
    WNDCLASSEX wcex = {0};
    wcex.cbSize        = sizeof(WNDCLASSEX);
    wcex.style         = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc   = WndProc;
    wcex.cbWndExtra    = DLGWINDOWEXTRA;
    wcex.hInstance     = hInstance;
    wcex.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP));
    wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wcex.lpszClassName = g_achWindowClass;
    wcex.hIconSm       = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APP));

    ATOM atom = RegisterClassEx(&wcex);
    if(atom == 0)
        return GetLastError();

    HWND hWnd = CreateDialog( hInstance,
                              MAKEINTRESOURCE(IDD_MAIN),
                              NULL,
                              NULL  );
    if(hWnd == NULL)
        return GetLastError();

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg = {0};
    while(GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_CREATE:
        {
            PostMessage(hWnd, MY_WM_INITDIALOG, 0, 0);
        }
        return 0;

        case MY_WM_INITDIALOG:
        {
            // subclass
            HWND hWndCtrl = GetDlgItem(hWnd, IDC_EDIT_TEST);
            g_pfnOldEditWndProc = (WNDPROC)GetWindowLongPtr(hWndCtrl, GWLP_WNDPROC);
            SetWindowLongPtr(hWndCtrl, GWLP_WNDPROC, (LONG_PTR)SubclassedEdit_WndProc);
        }
        return 0;

        case WM_DESTROY:
        {
            // unsubclass
            HWND hWndCtrl = GetDlgItem(hWnd, IDC_EDIT_TEST);
            SetWindowLongPtr(hWndCtrl, GWLP_WNDPROC, (LONG_PTR)g_pfnOldEditWndProc);

            PostQuitMessage(0);
        }
        return 0;

        case WM_CONTEXTMENU:
        {
            // WM_CONTEXTMENU point uses screen coords, but RealChildWindowFromPoint
            // uses client coords, so have to convert
            POINT ptScreen = {LOWORD(lParam), HIWORD(lParam)};
            POINT ptClient = ptScreen;
            ScreenToClient(hWnd, &ptClient);

            HWND hWndChild  = RealChildWindowFromPoint(hWnd, ptClient);
            // RealChildWindowFromPoint can find controls inside group boxes,
            // whereas ChildWindowFromPoint can find a groupbox before its children

            HWND hWndStatic = GetDlgItem(hWnd, IDC_STATIC_TEST);
            HWND hWndEdit   = GetDlgItem(hWnd, IDC_EDIT_TEST);
            HWND hWndButton = GetDlgItem(hWnd, IDCLOSE);
            if(hWndChild == hWndStatic)
                MessageBox(hWnd, _T("WM_CONTEXTMENU inside Static control"), _T("Subclass Test"), MB_ICONINFORMATION);
            else if(hWndChild == hWndEdit)
                MessageBox(hWnd, _T("WM_CONTEXTMENU inside Edit control"), _T("Subclass Test"), MB_ICONINFORMATION);
            else if(hWndChild == hWndButton)
                MessageBox(hWnd, _T("WM_CONTEXTMENU inside Button"), _T("Subclass Test"), MB_ICONINFORMATION);
            else
                MessageBox(hWnd, _T("WM_CONTEXTMENU somewhere else"), _T("Subclass Test"), MB_ICONINFORMATION);
        }
        return 0;

        case WM_COMMAND:
        {
            int nID = LOWORD(wParam);

            switch(nID)
            {
                case IDCLOSE:
                case IDCANCEL: // for [x] button
                {
                    DestroyWindow(hWnd);
                    return 0;
                }
                // No need for break;
            }
        }
        // fall through

        default:
        {
            return DefDlgProc(hWnd, message, wParam, lParam);
        }
    }

    return 0;
}

LRESULT CALLBACK
SubclassedEdit_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lReturn = TRUE;

    switch(uMsg)
    {
        case WM_CONTEXTMENU:
        {
            HWND hWndParent = GetParent(hWnd);
            PostMessage(hWndParent, uMsg, wParam, lParam);
            lReturn = 0;
        }
        break;

        default:
        {
            lReturn = CallWindowProc(g_pfnOldEditWndProc, hWnd, uMsg, wParam, lParam);
        }
    }

    return lReturn;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// subclass_test.rc

#include "resource.h"
#include "windows.h"

#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif

// Icon

IDI_APP  ICON  "app.ico"

// Dialog

IDD_MAIN DIALOGEX 9, 26, 281, 74
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION
CAPTION "Subclass Test"
CLASS "Subclass_Test_WndClass"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
    GROUPBOX        "Example controls",IDC_STATIC,9,10,261,34,0,0
    LTEXT           "Static",IDC_STATIC_TEST,18,23,82,12
    EDITTEXT        IDC_EDIT_TEST,108,23,144,12,ES_AUTOHSCROLL,0
    DEFPUSHBUTTON   "&Close",IDCLOSE,220,53,50,14
END


1
2
3
4
5
6
7
8
9
10
// resource.h

#define IDC_MYICON                      1
#define IDD_MAIN                        100
#define IDM_EXIT                        101
#define IDI_APP                         102
#define IDR_MAINFRAME                   103
#define IDC_STATIC_TEST                 104
#define IDC_EDIT_TEST                   105
#define IDC_STATIC                      -1 


Last edited on
looks like I kinda explained it wrong, so I'll try to make it as clear as possible :P

#1 I'm using SS_NOTIFY for every static control I want to work with

-RBUTTONDOWN:

-TabOneDlgProc:

-Clicking on Empty Space in Dialog works
-Clicking on ANY control don't works

-LBUTTODOWN

-same as RBUTTON

-CONTEXTMENU

-TabOneDlgProc

-clicking anywhere works, except edit control (that makes sense since edit control is calling its own CONTEXTMENU message)



now I want to bring messagebox ONLY when I click on IDC_HEROIMAGE with RBUTTON, since RBUTTONDOWN is not working I'm using CONTEXTMENU, instead of

1
2
3
4
5
	case WM_CONTEXTMENU:
		{
			MessageBox(hWnd, NULL, NULL, NULL);
			break;
		}


(used to find if CONTEXTMENU works)

I use

1
2
3
4
5
6
	case WM_CONTEXTMENU:
		{
			if(wParam == IDC_HEROIMAGE)
				MessageBox(hWnd, NULL, NULL, NULL);
			break;
		}


which is not working (it never displays messagebox), even when I try HI or LO WORD

I tried to add

1
2
3
			char tmp[32];
			wsprintf(tmp, "%d", HIWORD(wParam));
			MessageBox(hWnd, tmp, tmp, NULL);


but this gives me kinda random number, not actual ID of control

MSDN:

wParam
A handle to the window in which the user right-clicked the mouse. This can be a child window of the window receiving the message. For more information about processing this message, see the Remarks section.


so what I need is a way to find if "CONTEXTMENU" is called while clicking on IDC_HEROIMAGE (except the coords thing)





EVERYTHING I do, I do in TabOneDlgProc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
BOOL CALLBACK TabOneDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	switch(msg)
	{
	case WM_INITDIALOG:
		{
			for(int i = 0; i < 2; i++)
				SendMessage(GetDlgItem(hWnd, IDC_FACTION), CB_ADDSTRING, NULL, (LPARAM)Faction[i].c_str());
			SendMessage(GetDlgItem(hWnd, IDC_FACTION), CB_SETCURSEL, (WPARAM)0, NULL);
			for(int i = 0; i < 3; i++)
				SendMessage(GetDlgItem(hWnd, IDC_PRIMATT), CB_ADDSTRING, NULL, (LPARAM)PAtt[i]);
			SendMessage(GetDlgItem(hWnd, IDC_PRIMATT), CB_SETCURSEL, (WPARAM)0, NULL);
			HANDLE hBitmap = LoadImage(g_hInst, MAKEINTRESOURCE(IDB_DEFAULT), IMAGE_BITMAP, 128, 128, NULL);
			SendMessage(GetDlgItem(hWnd, IDC_HEROIMAGE), STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
			break;
		}
	case WM_CONTEXTMENU:
		{
			LPPOINT a;
			a->x = HIWORD(lParam);
			a->y = LOWORD(lParam);
			ScreenToClient(hWnd, a);
			break;
		
	case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
				break;
			}
			switch(HIWORD(wParam))
			{
			case STN_CLICKED:
				{
//stuff to do when I leftclick on static control, working well
					break;
				}
				break;
			case CBN_SELCHANGE:
				{
					if((HWND)lParam == GetDlgItem(hWnd, IDC_PRIMATT))
					{
						int ItemIndex = SendMessage((HWND)lParam, CB_GETCURSEL, NULL, NULL);
						Hero.PrimaryAtt = PAtt[ItemIndex];
						int a = Hero.PrimaryAtt[0];
						a+=32;
						Hero.PrimaryAtt[0] = a;
					}
					break;
				}
			}
		}
	case WM_CTLCOLORSTATIC:
		{
			if((HWND)lParam == GetDlgItem(hWnd, IDC_SSTR))
			{
				SetBkMode((HDC)wParam,TRANSPARENT);
				SetTextColor((HDC)wParam, RGB(255,0,0));
				return (BOOL)CreateSolidBrush (GetSysColor(COLOR_MENU));
			}
			else if((HWND)lParam == GetDlgItem(hWnd, IDC_SAGI))
			{
				SetBkMode((HDC)wParam,TRANSPARENT);
				SetTextColor((HDC)wParam, RGB(0,255,0));
				return (BOOL)CreateSolidBrush (GetSysColor(COLOR_MENU));
			}
			else if((HWND)lParam == GetDlgItem(hWnd, IDC_SINT))
			{
				SetBkMode((HDC)wParam,TRANSPARENT);
				SetTextColor((HDC)wParam, RGB(0,0,255));
				return (BOOL)CreateSolidBrush (GetSysColor(COLOR_MENU));
			}
			else if((HWND)lParam == GetDlgItem(hWnd, IDC_SARMOR))
			{
				SetBkMode((HDC)wParam,TRANSPARENT);
				SetTextColor((HDC)wParam, RGB(0,200,200));
				return (BOOL)CreateSolidBrush (GetSysColor(COLOR_MENU));
			}
			else if((HWND)lParam == GetDlgItem(hWnd, IDC_SMOVESPEED))
			{
				SetBkMode((HDC)wParam,TRANSPARENT);
				SetTextColor((HDC)wParam, RGB(200,0,200));
				return (BOOL)CreateSolidBrush (GetSysColor(COLOR_MENU));
			}
			else
				return 0;
			break;
		}
	}
	return FALSE;
}


edit: didn't notice your code, gonna try to modify mine to match yours "window" finding, will report soon

edit2: okay, looks like everything I was doing wrong with coords was not using "&p" but "p" as second argument in ScreenToClient function, anyway I'm still curious about first problem (#1) in this post
Last edited on
#1

The wParam is the window handle, not the control ID.

So, sorry, I was being a bit dopey. You can test this wParam value against GetDlgItem with IDC_HEROIMAGE.

(there are situation where the other approach ight be needed, but prob. not here).

#2

Here, you need to use the address-of operator (&)

1
2
3
4
    POINT p;
    p.x = HIWORD(lParam);
    p.y = LOWORD(lParam);
    ScreenToClient(hWnd, &p); // pass address here 


(this trick is required for a number of other Win32, like GetClientRect)
Last edited on
I already did that (edited my post :P) I'm just curious now about the first problem, with wParam, getting control without coords

#2

when creating menu I have to use this to get sub menu

1
2
3
4
5
6
7
8
9
10
11
12
13
	case WM_CONTEXTMENU:
		{
			POINT pScreen = {LOWORD(lParam), HIWORD(lParam)};
			POINT pClient = pScreen;
			ScreenToClient(hWnd, &pClient);
			HWND hChild = RealChildWindowFromPoint(hWnd, pClient);
			HMENU hMenu, hSubMenu;
			hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_HIMENU));
			hSubMenu = GetSubMenu(hMenu, 0);
			if(hChild == GetDlgItem(hWnd, IDC_HEROIMAGE))
				TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, pScreen.x, pScreen.y, 0, hWnd, NULL);
			break;
		}


what do I have to use when I actually want to show whole menu ?

let's say my menu looks like this:

File:
-Open
-Close
Tools:
-Tool1
-Tool2

when I usse submenu it will only show Open+Close or Tool1+Tool2 (depends on which submenu I chose)

but how do I show File/Tools where you can mouseover and it will popup (with >) Open/Close or Tool1/2 just like when you go to start > all programs ... I hope u udnerstand :P do I have to create submenu in submenu or is it possible to actually show whole menu?

edit: acutally I was testing it like tht at first, but it didn't work because

error C2446: '==' : no conversion from 'HWND' to 'WPARAM'

I just now realized that

(HWND)wParam works fine :/
Last edited on
How is your menu defined?

Like this?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDR_HIMENU MENU
{
    POPUP "File"
    {
        MENUITEM "Open" , IDM_FILE_OPEN
        MENUITEM "Close", IDM_FILE_CLOSE
    }
    POPUP "Tools"
    {
        MENUITEM "Tool1", IDM_TOOLS_TOOL1
        MENUITEM "Tool2", IDM_TOOLS_TOOL2
    }
}


TrackPopupMenu only works with popups

From MSDN

A handle to the shortcut menu to be displayed. The handle can be obtained by calling CreatePopupMenu to create a new shortcut menu, or by calling GetSubMenu to retrieve a handle to a submenu associated with an existing menu item.

So, this should work (if you use hSubMenu)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDR_HIMENU MENU
{
    POPUP "Context Menu"
    {
        POPUP "File"
        {
            MENUITEM "Open" , IDM_FILE_OPEN
            MENUITEM "Close", IDM_FILE_CLOSE
        }
        POPUP "Tools"
        {
            MENUITEM "Tool1", IDM_TOOLS_TOOL1
            MENUITEM "Tool2", IDM_TOOLS_TOOL2
        }
}


Andy
Last edited on
I have this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDR_HIMENU MENU
{
    POPUP "test"
    {
        POPUP " test1"
        {
            MENUITEM "test2", IDM_ASD2
        }
    }
    POPUP "asd"
    {
        MENUITEM "test3", IDM_ASD1
    }
}


which is working fine, when I want to call test1/test2 I use submenu 0 and submenu 1 for test3, I was just curious if I can call WHOLE menu just like you create it for window, but it's not important at all, thanks as usual!
Topic archived. No new replies allowed.