Two CEdit controls updating each other: infinite loop

I have on my dialog two text edit boxes. The idea is that when the contents of one is changed, the other changes and vice versa. I respond to the EN_CHANGE message (which I thought only fired in response to USER editing).

Needless to say, one EN_CHANGE invokes SetWindowText() in the other control, which causes another EN_CHANGE the other way, and so on ad infinitum.

I could just compare the "new" text with the existing text and do nothing if they are the same.

However, this won't work here because the text results from floating point numbers, so an exact textual match is not a good idea.

It is a simple dialog-based tool to convert kW to HP and vice versa. I don't want to have the user click any buttons to start the conversion; I just want the "other" box to update as the user types in "this" box.

How do I prevent this chain of EN_CHANGE messages ?
Is there a CEdit::SetWindowTextWithoutSendingAnUpdateMessage() call ?

Richard [in LU1]
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AndyAinscowFreelance programmer / ConsultantCommented:
If the focus is eg. in the first edit box then for the 'change' event in the second don't perform any processing.

if(GetFocus() == GetDlgItem(IDC_EDIT1))  return;

or similar code
Jaime OlivaresSoftware ArchitectCommented:
just create a couple of boolean members to avoid them to update
At first EN_CHANGE, set the boolean member to false and change the second control contents.
at second controls's EN_CHANGE event, first check the boolean variable to check if you are allowed to validate or not.
muttley3141Author Commented:
I'm currently doing what JO suggests, guarding things with simple boolean variables. This works, for now.

When the contents of CEdit #1 changes, the handler for that control (member of the containing CDialog-derived class) does this:

Sets ignchg = true;
Computes new text for CEdit #2
Calls SetWindowText() with that new text for CEdit #2
Sets ignchg = false;

Doing this will, of course, fire the handler for CEdit #2. That handler will see the ignchg set to true, and if it is, do nothing further, breaking the infinite cycle. If it is set to false, it will compute a new value for CEdit #1 in a symmetrical manner.

However, there is a problem with this: SetWindowText() resolves into SendMessage(WM_SETWINDOWTEXT..) or some such (or I presume it does).

What happens if the SendMessage() call puts the message into the queue of the CEdit #2, and returns before CEdit #2 has had time to pluck that message out of its queue, and act upon it ? By the time it gets around to acting on it, the return from SendMessage() may well cause the boolean to be set back to false.

I'm surprised this works at all at the moment.

My understanding is that a similar thing will happen if I use the "Do I have focus" test.
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

AndyAinscowFreelance programmer / ConsultantCommented:
>>My understanding is that a similar thing will happen if I use the "Do I have focus" test.

Why - the focus is not being changed in the sending of messages.
muttley3141Author Commented:
AA>>My understanding is that a similar thing will happen if I use the "Do I have focus" test.

> Why - the focus is not being changed in the sending of messages.

The focus is indeed not being changed by the message, but the user could change the focus in between the message being sent and the message being received and acted upon. Such is the nature of sending messages: they are asynchronous.
AndyAinscowFreelance programmer / ConsultantCommented:
Yes, but to change the focus requires other messages to be sent (AFTER the change message) surely.
muttley3141Author Commented:
>Yes, but to change the focus requires other messages to be sent (AFTER the change message) surely.

I don't know whether there are methods to change the focus other than sending messages.

If focus *is* changed by a message, then how can you tell that the focus-changing message will happen *AFTER* the SetWindowText() message. I don't know what other messages are floating about the system, who's sending them, who's receiving them, or in what order they get processed.

The sequence of actions you are proposing is.

1. Control A sends a SetWindowText() message to control B.
2. <lots of other messages get sent, maybe some to control B. These may be focus-changing messages, or other messages>
3. Control B now receives the message
4. < lots of other messages sent>
5. Control B eventually gets round to handling the message.
6. Control B decides to send a message to Control A
7. <lots of other messages sent>
8. Control A receives the message
9. <lots of other messages sent>
10. Control A now handles the message. It bases its decision as to whether or not to "handle" the message by determining whether it itself has focus.

By the time "10" happens, it may well have lost its original focus (which caused it to send the message at "1") due to all the other messages flying around.

What's to stop the user pressing TAB to move the focus between the controls at any point between 2 and 9 ?

Far be it from me to contradict a Genius, but there's obviously something here that you know well and take for granted, but which is passing me by. I seem to be taking the nature of windows messaging to
be more unpredicitable than it is. Please tell me that I am wrong, quite wrong.

Richard [in SG1]
AndyAinscowFreelance programmer / ConsultantCommented:
MFC is single threaded (well it is explicitly stated as NOT thread safe).
There is SendMessage which is synchronous and PostMessage which is assynchronous.  AFAIK the SetWindowText calls the SendMessage functions.
The message pump is on a per app basis, not a per control basis.
muttley3141Author Commented:
Ahah !

So are you saying that when part of my program calls SendMessage(), it is effectively simply calling the recipient's WindowProc, and is explicitly not "queuing" or "holding" anything ?

Are you saying that a call to SendMessage() returns when and only when its work is done ?

Assuming that SetWindowText() does call into SendMessage (as opposed to PostMessage), does this mean that the SetWindowText() has already done its work completely by the time it returns to the caller ?
(I realise, of course, that it could create a thread of its own if it really wanted to)

In other words, SendMessage() can't really fail in the way that PostMessage() can. Is my understanding correct ?

If I understand you correctly, then the naming of SendMessage() is very disingenuous: the word "send", to me, means "despatch something without any direct notification that it has reached its destination". Perhaps US usage of Post versus Send is significant; in UK English, they are effectively synonymous.

If so, then both your and JO's solutions are equally valid. JO's is what I am doing at the moment, but I will try your solution: it's less messy.

AndyAinscowFreelance programmer / ConsultantCommented:
Have a look at SendMessage and PostMesssage in help - they are very different in operation.  Important to understand that.

>>So are you saying that when part of my program calls SendMessage(), it is effectively simply calling the recipient's WindowProc,
Both edits are in the same app - so the same message pump feeds both WindowProc's
muttley3141Author Commented:
Yes, SendMessage() returns when the underlying job is finished, and PostMessage() puts the item into the queue if it can, and returns immediately.

My problem is with the definition of "underlying job".

The phrase "message pump" is a bit scary. I've heard it used before and I'm not quite sure what it's referring to. It conjures up images of long queues of messages "waiting".

Can you explain what a message pump is, please ? Is it just a Windows-ism for "message queue" or does it have a specific meaning ?

If MFC is single-threaded, I don't see how there can be a queue within the application.

I'm obviously assuming Windows/MFC is much more asynchronous than it is.

I will look up the specifics of SendMessage()
AndyAinscowFreelance programmer / ConsultantCommented:
>>My problem is with the definition of "underlying job".
finish the *synchronous* processing involved in the message.

The message pump is the mechanism that windows uses to process messages in the queue.

>>If MFC is single-threaded, I don't see how there can be a queue within the application.

PostMessage(THIS);  PostMessage(THAT); PostMessage(THEOTHER);
Three messages are now waiting for the app to process them.  It can only process them once the app has CPU time to do so.

>>I'm obviously assuming Windows/MFC is much more asynchronous than it is.
Asynchronous is not the same as multithreaded (and it can behave asynchronously to the detriment of the programmer especially if one does not understand the difference between SendMessage and PostMessage - one sees number of questions here along the lines of 'what is wrong with this code segment....' ).

ps.  What I suggested I think should work but please attempt to break it - I would be interested to hear if you succeed.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
AndyAinscowFreelance programmer / ConsultantCommented:
Just a point for clarification.
You can use multiple threads with MFC apps.  Just do NOT pass any MFC objects between threads - you might be lucky and it functions in that particular release of MFC.  The 'correct' way to do it by passing window handles and using messages or other techniques to communicate between the threads.
muttley3141Author Commented:
Yes, I've done multi-threaded stuff on Windows before, but using Borland OWL. I'm not sure whether that is more/less thread-secure than MFC.

Is it safe, for example, if I have a "worker thread" which will take a long time, for that thread to e.g. update a CProgressBar in a dialog in the main thread ? I've always erred on the side of caution by sending a custom identifier as part of a WM_COMMAND message with the progress % in it, and having the "main" thread update said progress bar ?

I've seen Delphi programs which seem to talk directly to controls across threads, and it looks very scary.

I've never done it that way: I've always just "signaled" between threads using WM_COMMAND or whatever, and using getters/setters which I write myself and know to be thread-safe.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.