dialog box controls - detect changes - c++

I want to detect when any control on a dialog box is changed by user action. For example, when data is entered in a text box, a date is entered in a date-time picker, a check box is checked or unchecked, etc. Up to now I have ignored such notifications and simply retrieved the state of the controls when the user pushes some button but now I want to know a change has taken place (I want to enable the Apply button on a property sheet). I don't really care what change has taken place, all I want to know is that something has changed. By change I do NOT mean a change in focus but some actual action by the user to change a control.
I use plain old c++, no MFC or anything fancy.
How do I go about this?

You can test whether a checkbox has been checked with the BN_CLICKED notification code which you'd get through WM_COMMAND.
switch( uMsg ) {
...
case WM_COMMAND: {
switch( HIWORD( wParam ) ) {
case BN_CLICKED: {
if( Button_GetCheck( lParam ) == BST_CHECKED ) {
...
}
break;
}
default:
return false;
}
break;
}
default:
return false;
}
return true;
That is an example of how your DialogProc might be set up. You can switch on lParam or LOWORD( wParam ) to identify which button.

Related

Find mfc mainframe OnCommand message for "33614080"

Edit 3: This is no good--the Right arrow key is sent every time the window loses focus--bad behavior.
I tried intercepting when the user clicks the close box, but so far I have not been able to find it in the class wizard. If anyone knows how to detect this event, please let me know.
Original post(s):
Edit 2: I have edited the code for a solution that does not use a magic number, but as Mark Ransom has noted, this is not the proper way to select a specific button for an input prompt, so this may work correctly, but it is a hack.
I have a legacy application in MFC that has a prompt when exiting to save changes. When the input prompt opens, the 'No' button should be selected when it prompts the user to save changes in the CMainFrame window. This is so that the user can press the Enter key to exit without having to use the mouse to select it. And yes, I am aware that the user can simply press the 'N' key to activate the 'No' button, but the 'No' button needs be selected so the user can press the Enter key to exit.
Using the message loop in:
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
I can detect a message when the window is closing, before being prompted to save changes.
So I added this numeric value and I am sending the right arrow key to select 'No' in the input message prompt.
EDIT: Added beginning of switch statement to show what is being evaluated.
// this is part of 'BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)'
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
switch( wParam )
{
...
//case 33614080:
//SendRightArrowKey();
//break;
default:
WORD loWord = LOWORD(wParam);
if (ID_RECORD_FIRST == loWord)
{
WORD HiWord = HIWORD(wParam);
unsigned short value = HiWord;
char buff[32];
_itoa(value, buff, 10);
if (EN_KILLFOCUS == value )
{
SendRightArrowKey();
}
return TRUE;
}
}
return CFrameWnd::OnCommand(wParam, lParam);
}
void SendRightArrowKey()
{
INPUT output[2];
ZeroMemory(&output, sizeof(output));
// Right arrow key down
output[0].type = INPUT_KEYBOARD;
output[0].ki.wVk = VK_RIGHT;
output[0].ki.time = 0;
output[0].ki.dwExtraInfo = 0;
// Right arrow key up
output[1].type = INPUT_KEYBOARD;
output[1].ki.wVk = VK_RIGHT;
output[1].ki.dwFlags = KEYEVENTF_KEYUP;
output[1].ki.time = 0;
output[1].ki.dwExtraInfo = 0;
int retval1 = SendInput(2, output, sizeof(INPUT));
}
This works for win32 and x64, but it feels like a hack--especially because I can't find any definition for the numeric code 33614080. There should be constant or a macro for the windows message that gets sent for the WParam, in case Microsoft ever changes this value.
Does anyone know of a constant that this WParam value might represent,
or another way to have the 'No' button selected by default?
Thanks in advance for any replies.
Thanks Adrian for figuring out the values.

why my windows receive en_setfocus 12 times

I want to be notified when user click the password text field.
But when I do click the password text field, the following function is called more than once:
void CUserDlg::OnSetfocusPasswordEdit()
{
// TODO: Add your control notification handler code here
cout << "focus on password text field";
}
Why does this happen ?
I also tried :
LRESULT CFakeUserDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
switch (message)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_PASSWORD_EDIT:
if (HIWORD(wParam) == EN_SETFOCUS)
{
cout << "";
}
cout << "";
break;
}
.
.
.
This also happens many times when I click the text field only once.
I just tried to spy++, but it shows that spy++ caputure edit control messages, but EN_SETFOCUS is not message, it is edit control notification.
I got answer by myself.
Edit control does keep sending EN_SETFOCUS when it gets the focus.

How to detect current active page in Property sheet (C++/VS)

I am using Visual Studio C++ 2010, and I need to detect current active page of Property Sheet. I expect there should be send some message to tell when user activated the Page. But I did not found that message and where to place it in dialog process.
In the program which I work with, there is this main dialog process:
INT_PTR CALLBACK MainDlgProc(HWND hSheet, UINT msg, WPARAM wParam, LPARAM lParam)
{
INT_PTR ret = FALSE;
switch (msg)
{
// bla bla
case WM_COMMAND:
ret = 0; //processing message
if (!Sheet_HandleCommand(hSheet, HIWORD(wParam), LOWORD(wParam), (HWND)lParam))
CALLPROC();
break;
case WM_DESTROY:
// bla bla
return CALLPROC();
default:
return CALLPROC();
}
return ret;
}
I know how to get the handle but I don't know where to "install" it in the code. What's the name of the message to include it into the MainDlgProc?
Use PSM_GETTABCONTROL (or the PropSheet_GetTabControl macro) to get a handle to the tab control, and then use the TCM_GETCURSEL message (or the TabCtrl_GetCurSel macro) to query the currently selected tab index.
Note this is documented not to work if using the Aero wizard style (PSH_AEROWIZARD), presumably because there is no tab control in that case.

Reset cursor in WM_SETCURSOR handler properly

INTRODUCTION AND RELEVANT INFORMATION:
I have made an application that needs to change the look of a cursor into hand when mouse hovers above the static control, but resets it to a normal cursor otherwise.
My initial application was in full screen mode, but recently terms have changed and it must have a resizable window.
This means that my handler for WM_SETCURSOR must be rewritten to reflect newly introduced changes.
Cursors are loaded in WM_CREATE, and I have defined class cursor, like this:
// cursors
case WM_CREATE:
hCursorHand = LoadCursor( NULL, IDC_HAND );
hCursorArrow = LoadCursor( NULL, IDC_ARROW );
// other stuff
In my class:
WNDCLASSEX wc;
// ...
wc.hCursor = hCursorArrow;
//...
This is my old WM_CURSOR handler ( code is simplified for clarity purposes ):
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
SetCursor(hCursorHand);
else
SetCursor(hCursorArrow);
return TRUE;
If cursor hovers above static control, then my handler changes it to hand, else sets it to default cursor ( arrow ).
Bellow is the picture I have sketched in Paint that displays the desired look of the cursor when it hovers above static control, it is on the client area, and when user resizes window.
If additional code snippets are required, ask and I will edit my post, but for now, they are omitted to keep the post short and concise.
I work on Windows XP, using MS Visual Studio C++ and pure Win32 API.
MY EFFORTS TO SOLVE PROBLEM:
Bellow are the code snippets that I have tried, but they all failed:
First snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
return DefWindowProc( hWnd, msg, lParam, wParam );
Second Snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
break; // based on MSDN example
Third snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
return FALSE;
These set cursor to hand no matter where it is.
If I leave my WM_SETCURSOR handler unchanged, the only problem I get is that instead of sizing arrows, I get regular arrow ( as the cursor’s look ) when I hover over the border, but window can be sized.
If I comment out my WM_SETCURSOR handler, sizing arrows and cursor arrow appear properly, but cursor doesn’t change into hand when hovers above static control ( which is logical, since there is no WM_SETCURSOR handler to change it ).
I have browsed through SO archive, looked on MSDN, CodeProject , DaniWeb, Cprogramming and CodeGuru, but had no success.
Looking through those, I have found an example where people compare low word of the lParam against hit test code.
Looking through MSDN I have found link for hit test values ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx ) and I have found link for cursor types (http://msdn.microsoft.com/en-us/library/windows/desktop/ms648391%28v=vs.85%29.aspx ).
Currently I am reading them, because I think that I will have to load additional cursor resources, take several comparisons of hit test values, and then use those resources to set cursor look accordingly.
QUESTION:
I really would like my WM_SETCURSOR handler to look like this:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
// reset cursor's look to default
so I ask the community to instruct me on how to do this.
If this isn’t possible, then I will consider using multiple if statements to check the hit test code, and set cursor’s look accordingly.
Of course, if there is better solution for my problem, please suggest it, I will consider it as well.
Thank you.
Regards.
In general, if you handle the WM_SETCURSOR message you must either
Call SetCursor() to set the cursor, and return TRUE, or
If the message came from a child window, return FALSE for default processing, or
If the message is from your own window, pass the message through to DefWindowProc()
I think the last two points aren't made quite clear by the MSDN docs.
The window under the mouse pointer gets the first WM_SETCURSOR message. If it handles it and returns at that point, nothing else happens. If however it calls DefWindowProc(), then DWP forwards the message to the window's parent to handle. If the parent chooses not to handle it, it can return FALSE and the DefWindowProc processing will continue.
But this only applies if the message came from a previous call to DWP. If the message originated with the window itself, rather than a child, returning TRUE or FALSE without setting the cursor means the cursor won't be set at all.
Another thing: although your question didn't specify, I'm assuming from your use of GetDlgItem() that your top-level window is a dialog. If that's true, you can't just return TRUE or FALSE for a message - you need to return the value using SetWindowLongPtr() and store the return value in DWLP_MSGRESULT. Returning FALSE from a dialog procedure indicates that you didn't handle the message at all - this is equivalent to passing a message through to DefWindowProc().
So I think the proper handling for your situation is, in your top-level window:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
return TRUE;
}
return FALSE;
If your top-level window isn't in fact a dialog, you would do this:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
Here's my first example, if cursor go to menubar, cursor changes to cursor hand:
HCURSOR cursorHand = LoadCursor(NULL, IDC_HAND);
case WM_SETCURSOR:
if(LOWORD(lParam) == HTMENU)
{
SetCursor(cursorHand);
}
break;
Here's my second example, if cursor goes to button, cursor changes to cursorHand:
HCURSOR cursorHand = LoadCursor(NULL, IDC_HAND);
case WM_SETCURSOR:
if(LOWORD(lParam) == buttonId)//declare you
{
SetCursor(cursorHand);
}
break;
Warning:menubar and button is not created! Create you and please, check my answer example.
The question as I understand it is, given a parent window with one more more child windows (one of which is a static control) how do you set the cursor to the hand when the cursor is over the static control, and the arrow when the cursor is over the client area of the parent window, and let default processing take place when the cursor is over a non-client area of the parent window.
To check things out, I wrote a simple program with a top-level window with a static control as a child window. My first attempt was the following:
1) Set the class cursor of the top-level window to LoadCursor(NULL, IDC_ARROW). This allows the default processing to set the cursor to the arrow when appropriate.
2) Keep track of the position of the mouse cursor by handling the WM_MOUSEMOVE message by calling my HandleWMMouseMove function as follows:
case WM_MOUSEMOVE:
HandleWMMouseMove(lParam);
break;
//ptCurrMousePos is a global variable of type POINT
static void HandleWMMouseMove(LPARAM mousepos)
{
ptCurrMousePos.x = (int)(short)(LOWORD(mousepos));
ptCurrMousePos.y = (int)(short)(HIWORD(mousepos));
}
3) and then all I had to do was handle the WM_SETCURSOR message by calling my HandleWMSetCursor function as follows:
case WM_SETCURSOR:
if (HandleWMSetCursor())
return TRUE;
break;
//hwndFrame is a handle to the top-level window.
//hwndStatic is a handle to the static control.
static BOOL HandleWMSetCursor(void)
{
if (ChildWindowFromPoint(hwndFrame, ptCurrMousePos)==hwndStatic) {
SetCursor(hCursorHand);
return TRUE;
}
return FALSE;
}
this worked fine but I couldn't understand how the code posted in the question was working even partially. So I asked the questioner whether the child window was really a static control. The answer was yes but it was created with the SS_NOTIFY style. So I created my child window with this style and my code stopped working, but the code posted with the question started to work. With the help of the Spy++ program distributed with Visual Studio I learned the following.
Static controls are normally transparent (not in the visual sense, but meaning that even when the mouse is over the transparent window, Windows will consider the mouse to be over the window underneath the transparent window).
When you create a static control with SS_NOTIFY the control is no longer transparent (i.e. it starts to receive an process mouse messages (like WM_MOUSEMOVE), so my code stopped working because it never received WM_MOUSE messages when the cursor was over the static control. On the other hand the code in the question did not work when the static control was created without SS_NOTIFY because without this style the static control was transparent, which meant that the WARAM in the WM_SETCURSOR message was never equal to the static control (in other words Windows never considered the mouse to be over the static control because it was transparent).
It is possible to combine the two approaches by changing the WM_SETCURSOR handler function to the following:
//hwndFrame is a handle to the top-level window.
//hwndStatic is a handle to the static control.
static BOOL HandleWMSetCursor(WPARAM wParam)
{
if (((HWND)wParam == hwndStatic) || (ChildWindowFromPoint(hwndFrame, ptCurrMousePos)==hwndStatic)) {
SetCursor(hCursorHand);
return TRUE;
}
return FALSE;
}

C++ Checkbox's acting like radio buttons WINAPI ( No MFC )

I am trying to get 2 checkboxs in my application to act like radio buttons. IE - When one is ticked the other button will untick itself. I dont believe that this can be achieved through the properties menu so I am trying to do it in code.
I dont know much about how to do this at all so I am getting a bit lost. This is what I have so far (which Is not working)
case BN_CLICKED:
if(BN_CLICKED == IDC_CHECK_MW){
SendMessage(GetDlgItem(hDlg,IDC_CHECK_MW), BM_GETCHECK, (WPARAM)0 ,(LPARAM)0) == BST_CHECKED;
}
I may be way oof but any help would be great!
If you have the handles or something handy, just send a BM_SETCHECK:
int checkState = SendMessage (otherHwnd, BM_GETCHECK, 0, 0);
SendMessage (otherHwnd, BM_SETCHECK, checkState == BST_CHECKED ? BST_UNCHECKED : BST_CHECKED, 0);
This of course assumes that it can only be checked or unchecked, not in an intermediate state. I would also really reconsider your thinking, as checkboxes are meant to act as such, and radio buttons are the right tools for this behaviour.
Also, in your message switch, you want this probably:
case WM_COMMAND:
{
if (HIWORD (wParam) == BN_CLICKED)
{
switch (LOWORD (wParam))
{
case IDC_CHECK_MW:
//check this, uncheck that
break;
case IDC_OTHER_CHECK:
//check other, uncheck first
break;
default:
//something went wrong
}
}
}