Solved

Monitor EDIT control

Posted on 2013-05-25
13
404 Views
Last Modified: 2013-05-27
I have an EDIT control, and during the entire execution of my program, I need to monitor this field to see if the number "7" was entered.

It doesn't matter what the final value of the EDIT control is, I just need to know if at ANY time, a 7 was entered.

Can someone show me a code snippet example?

Thank you
0
Comment
Question by:edvinson
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 5
13 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 39197877
You could use a Windows hook (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632589%28v=vs.85%29.aspx) for that which monitors keypress events and checks if they occurred in your edit control, e.g. like

#include <windows.h>

HHOOK g_hhk;
HWND g_hEdit;

LRESULT CALLBACK GetMsgProc(
    int code,
    WPARAM wParam,
    LPARAM lParam
)
{
    if (o > code || PM_NOREMOVE == wParam) return CallNextHookEx(g_hhk,code,wParam,lParam);

    MSG* pmsg = (MSG*) lParam;

    if (pmsg->message == WM_KEYDOWN) { // this one is for us

        if (pmsg->hwnd == g_hEdit && pmsg->wParam == VK_7) { // '7' has been pressed if the monitored edit control

            // ---> ACTION!
        }
    }

    return CallNextHookEx(g_hhk,code,wParam,lParam);
}

void InitMonitoring(HWND hEdit) {

    h_hEdit = hEdit;

    g_hhk = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,NULL,GetCurrentThreadId());
}

void StopMonitoring() {

    UnhookWindowsHookEx(g_hhk);
}

Open in new window

0
 
LVL 1

Author Comment

by:edvinson
ID: 39198345
Wow thanks! I just don't know where to implement it, could you show me so I can test it?
Was your code intended to be used in a Dialog based app?


Here is my complete source code:

#include <windows.h>


#include "resource.h"


//---------------------------------------------------------------------------
HWND hWnd;
LRESULT CALLBACK DlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine, int nCmdShow)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1),
	          hWnd, reinterpret_cast<DLGPROC>(DlgProc));

	return FALSE;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch(Msg)
	{
	case WM_INITDIALOG:
		return TRUE;

	case WM_COMMAND:
		switch(wParam)
		{
		case IDOK:
             
			EndDialog(hWndDlg, 0);
			
			
			
			
			return TRUE;
		}
		break;
	}

	return FALSE;
}
//---------------------------------------------------------------------------
                                  

Open in new window


Maybe we can just show a messagebox when the 7 is pressed so I can test.

Thanks
0
 
LVL 1

Author Comment

by:edvinson
ID: 39198347
almost forgot, let's use IDC_EDIT1 as my textfield we are monitoring, ok?

Thank you. I am currently blindly trying to put your code into my project, but I am new to c++
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 86

Expert Comment

by:jkr
ID: 39198355
You could do that in any kind of app, all you need the window handle of the control. E.g. like

InitMonitoring(GetDlgItem(IDC_EDIT1));

Open in new window

0
 
LVL 1

Author Comment

by:edvinson
ID: 39198364
I feel stupid, you have clearly explained this, but I cannot get this to compile.

Could you show me exactly where to put your working code in the code sample I posted above, please?
0
 
LVL 86

Expert Comment

by:jkr
ID: 39198366
What compier errors are you getting?
0
 
LVL 86

Expert Comment

by:jkr
ID: 39198370
One thing, that should be a '0' instead of an 'o' in

    if (o > code || PM_NOREMOVE == wParam) return CallNextHookEx(g_hhk,code,wParam,lParam);

Open in new window


i.e.

    if (0 > code || PM_NOREMOVE == wParam) return CallNextHookEx(g_hhk,code,wParam,lParam);

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 39198373
OK, along with your code, that should be

#include <windows.h>


#include "resource.h"

HHOOK g_hhk;
HWND g_hEdit;

LRESULT CALLBACK GetMsgProc(
    int code,
    WPARAM wParam,
    LPARAM lParam
)
{
    if (0 > code || PM_NOREMOVE == wParam) return CallNextHookEx(g_hhk,code,wParam,lParam);

    MSG* pmsg = (MSG*) lParam;

    if (pmsg->message == WM_KEYDOWN) { // this one is for us

        if (pmsg->hwnd == g_hEdit && pmsg->wParam == VK_7) { // '7' has been pressed if the monitored edit control

            // ---> ACTION!
        }
    }

    return CallNextHookEx(g_hhk,code,wParam,lParam);
}

void InitMonitoring(HWND hEdit) {

    h_hEdit = hEdit;

    g_hhk = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,NULL,GetCurrentThreadId());
}

void StopMonitoring() {

    UnhookWindowsHookEx(g_hhk);
}
                                            


//---------------------------------------------------------------------------
HWND hWnd;
LRESULT CALLBACK DlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine, int nCmdShow)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1),
	          hWnd, reinterpret_cast<DLGPROC>(DlgProc));

	return FALSE;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch(Msg)
	{
	case WM_INITDIALOG:
                InitMonitoring(hwndDlg);
		return TRUE;

	case WM_COMMAND:
		switch(wParam)
		{
		case IDOK:
             
			EndDialog(hWndDlg, 0);
			
			
			
			
			return TRUE;
		}
		break;
	}

	return FALSE;
}
//---------------------------------------------------------------------------
                                  
                                            

Open in new window

0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 39198376
Oops, sorry - my bad, that should be

#include <windows.h>


#include "resource.h"

HHOOK g_hhk;
HWND g_hEdit;

LRESULT CALLBACK GetMsgProc(
    int code,
    WPARAM wParam,
    LPARAM lParam
)
{
    if (0 > code || PM_NOREMOVE == wParam) return CallNextHookEx(g_hhk,code,wParam,lParam);

    MSG* pmsg = (MSG*) lParam;

    if (pmsg->message == WM_KEYDOWN) { // this one is for us

        if (pmsg->hwnd == g_hEdit && pmsg->wParam == VK_7) { // '7' has been pressed if the monitored edit control

            // ---> ACTION!
        }
    }

    return CallNextHookEx(g_hhk,code,wParam,lParam);
}

void InitMonitoring(HWND hEdit) {

    h_hEdit = hEdit;

    g_hhk = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,NULL,GetCurrentThreadId());
}

void StopMonitoring() {

    UnhookWindowsHookEx(g_hhk);
}
                                            


//---------------------------------------------------------------------------
HWND hWnd;
LRESULT CALLBACK DlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine, int nCmdShow)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1),
	          hWnd, reinterpret_cast<DLGPROC>(DlgProc));

	return FALSE;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch(Msg)
	{
	case WM_INITDIALOG:
                InitMonitoring(GetDlgItem(hwndDlg,IDC_EDIT1));
		return TRUE;

	case WM_COMMAND:
		switch(wParam)
		{
		case IDOK:
             
			EndDialog(hWndDlg, 0);
			
			
			
			
			return TRUE;
		}
		break;
	}

	return FALSE;
}
//---------------------------------------------------------------------------
                                  
                                            
                                            

Open in new window

0
 
LVL 1

Author Closing Comment

by:edvinson
ID: 39198383
That is great. Thank you. One final question, if I wanted to monitor multiple controls, should I simply use:

InitMonitoring(GetDlgItem(hwndDlg,IDC_EDIT1));
InitMonitoring(GetDlgItem(hwndDlg,IDC_EDIT2));
InitMonitoring(GetDlgItem(hwndDlg,IDC_EDIT3));

etc? Or would you suggest I rewrite your code to handle multiple controls?
0
 
LVL 86

Expert Comment

by:jkr
ID: 39198387
Yes, multiple controls would require that to be rewritte, albeit not that differently - you'd basically make that

void InitMonitoring(HWND* phEdit, size_t count);

Open in new window


and store the handles in an array that you later evaluate inside 'GetMsgProc()' (also changing 'g_hEdit' to an array/pointer).
0
 
LVL 34

Expert Comment

by:sarabande
ID: 39199291
if you have a dialog form where the edit control is part of, it is easier to handle the EN_CHANGE notification for the edit control rather than hooking. hooking is the way if you don't own the control or don't have access to the dialog (sources).

WM_COMMAND 
wNotifyCode = HIWORD(wParam); // notification code 
wID = LOWORD(wParam);         // item, control, or accelerator identifier 
hwndCtl = (HWND) lParam;      // handle of control

Open in new window


EN_CHANGE 
idEditCtrl = (int) LOWORD(wParam); // identifier of edit control 
hwndEditCtrl = (HWND) lParam;      // handle of edit control

Open in new window



when using mfc you simply could add an event handler in the resource editor. select the edit control and choose 'add event handler' from right-click menu. or you override the PreTranslateMessage function of your mfc dialog class and check for WM_KEYDOWN message (similar as done in the hook).

when not using mfc go to the windows proc of your dialog and handle WM_COMMAND message.

case WM_COMMAND:
{
     WORD wNotifyCode = HIWORD(wParam); // notification code 
     WORD idEdit = LOWORD(wParam); 
     if (wNotifyCode == EN_CHANGE && idEdit == IDC_EDIT1)
     {
          char szEdit[256] = { '\0' };
          HWND hwndEdit = (HWND) lParam;
          GetWindowText( hwndEdit, szEdit, sizeof(szEdit));
          if (strchr(szEdit, '7')) 
          {
               // string contains '7'
               DWORD dwStart;
               DWORD dwEnd;
               wParam = (WPARAM) (LPDWORD) &dwStart; // receives starting position 
               lParam = (LPARAM) (LPDWORD) &dwEnd;   // receives ending position 
               SendMessage(hwndEdit, EM_GETSEL, wParam, lParam);
               if (dwStart == dwEnd && dwStart >= 0 && dwStart <= (DWORD)strlen(szEdit))
               { 
                    if (szEdit[dwStart] == '7')
                    {
                         // 7 was entered at caret (cursor) position
                    }
               }
         }
}

Open in new window



note, the code checking for the actual change would become easier if you save old value of edit control. then you only have to compare old value with new value to find out whether a '7' was entered.

note, if you use EN_UPDATE instead of EN_CHANGE the notification was sent before the edit control was displayed. you then can prevent the '7' to be displayed by calling SetWindowText.

Sara
0
 
LVL 1

Author Comment

by:edvinson
ID: 39200225
Thank you both so much! Sara, as always, I appreciate your thorough explanations and code examples.

JKR, I am attempting to re-write to accommodate multiple controls. Thanks again.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question