Re: WM_TIMER remaining/elapsed time...
Simon wrote:
On 2010/04/30 08:26 AM, Joseph M. Newcomer wrote:
You described something you thought you wanted, to solve an undefined
problem.
No, I asked 2 fairly straight forward questions, read my OP again.
is it possible to pause a timer and is there a way to know how many ms
remain.
...state what problem you were trying to solve, so we could not offer
suggestions about what
might actually do the job, because we didn't know what you were trying
to accomplish.
No, _you_ could not offer suggestions.
Others did, and they very good suggestions, thanks.
Actually, my own take on this is that if you have to keep checking as
you describe, you
need to redesign the application so this is not even a problem that
needs to be solved.
You are tyring to retrofit something into an existing app that it was
not designed to
handle, and you are probably approaching the problem incorrectly.
No, this is the wrong assumption.
I could write a book about the application and _then_ ask my question(s).
Or I could try to be as short and to the point as possible in order to
get some help/insight/tips.
Even the one example I gave had to be short and to the point.
Any programmer would understand that.
This is not an architecture design meeting room, this is a NG.
Regards,
Simon
Note speaking for Joe, what Joe was trying to express that you
(speaking in general) can get different answers when you provide a
small background or reason, this is especially true when you already
know the answer to the "pause" question about timers.
For example, in lieu of reasons, I provided an answer based on the
clues you provided:
::SetTimer( m_hWnd, TIMER_IDENT, 600000, NULL ); // WM_TIMER sent to
CWnd queue
where the hints here
- a Window handle m_hWnd, and
- a Timer ID
- A large frequency, 10 minutes
means you would have a CWnd::OnTimer() handler and you have the
ability to work with timer id passed to it to deal with the 10 minute
event. If you had another timer id with a different frequency, then
it normally means you need to check for the timer id event.
I find a lot of times people don't realize the timer id can be used in
the OnTimer(UINT nIDEvent) message even. Hence I provided one
implementation based the hints where you have a wait countdown with
the idea you can pause the countdown as you r original questions
"implied" - a pause in some "timer countdown." You didn't saw how
the pause happens, so I presumed it would be a button or something.
But after you followed up with the actual logic you are looking for:
OnTimer()
{
if( busy_doing_something_important )
{
// check again in 10 seconds
}
else
{
check_for_transactions()
}
}
that changes the picture and I would of provided a different answer as
it bring into question a "design" question of even needing this 10
minute timer, and also make the applet more dynamic, with no lost of
timed events.
In other words, its more dynamic for your check_for_transactions().
For example, you indicated you can be busy for more than one reason.
You didn't indicate the frequency of the check_for_transactions(), but
lets assume its done every 1 second because the recheck would be done
by seconds (every 10 secs).
So you could have a design where you have the following, and I will
show two versions of the following CBusyTask class to illustrate how
the requirements may alter depending on your implementations needs:
class CBusyTask {
public:
CBusyTask() : m_BusyCount(0) {}
void Clear() { m_BusyCount = 0; }
void Enter() { m_BusyCount++; }
void Exit() { if (m_BusyCount > 0) m_BusyCount--; }
BOOL IsBusy() { return m_BusyCount > 0; }
LONG Count() { return m_BusyCount; }
private:
LONG m_BusyCount;
};
The above CBusyTask class is safe for *Cooperative MultiTasking*
(cotask) implementations, such as within a GUI applications with
message events. If the busy actions are started by the a cotask
application, then the above is sufficient.
However, a more general CBusyTask that supports cotask and preemptive
multi-threads, then you need to support synchronization ideas. So
CBusyTask can be this now:
class CBusyTask {
public:
CBusyTask() : m_BusyCount(0) {}
void Clear() { InterlockedExchange(&m_BusyCount,0); }
LONG Enter() { return InterlockedIncrement(&m_BusyCount); }
LONG Exit() { return InterlockedDecrement(&m_BusyCount); }
BOOL IsBusy() { return m_BusyCount > 0; }
LONG Count() { return m_BusyCount; }
private:
LONG m_BusyCount;
};
So if these actions can occur from anywhere, it changes the
requirements for a "busy" flag.
If you add an CBusyTask m_Busy instance in your CWnd bsaed class or
make it global:
CBusyTask _g_Busy;
now in your OnTimer, it simplifies to this:
void CMyDialog::OnTimer(UINT nIDEvent)
{
if (nIDEvent == TIMER_IDENT) {
if (!_g_Busy.IsBusy()) {
check_for_transactions();
}
}
CMyDialog::OnTimer(nIDEvent);
}
You don't need an additional timer to wait. The CBusyTask will allow
you to keep a "reference count" of multiple actions either started in
a cooperating multi-tasking function or external multi-threaded
function that has access to the global _g_Busy.
As soon as all actions are done, the transaction checks can start with
no waiting.
All your actions will now just wrap the code of close with Enter() and
Exit() calls.
void CMyDialog::DoPrint()
{
_g_Busy.Enter();
... do printing ....
_g_Busy.Exit();
}
void CMyDialog::DoReport()
{
_g_Busy.Enter();
... do report ....
_g_Busy.Exit();
}
etc.
You can even get fancier, make it more robust and simplify coding of
not needing an explicit _g_Busy.Exit() call by using local scoping
ideas within your functions. So you can have something like this:
void CMyDialog::DoReport()
{
CBusyTaskGrabber grab(&_g_Busy);
... do report ....
if (whatever)
{
CBusyTaskGrabber grab(&_g_Busy);
... do whatever ...
} <--- Lost of Scope: grab instance destructor called
} <--- Lost of Scope: grab instance destructor called
where CBusyTaskGrabber is a wrapper class:
class CBusyTaskGrabber {
public:
CBusyTaskGrabber(CBusyTask *p) : pBusyTask(p) {pBusyTask->Enter();}
~CBusyTaskGrabber() {pBusyTask->Exit();}
private:
CBusyTask *pBusyTask;
};
that grabs a pointer to a CBusyTask instance to allow for automated
reference decrements upon the lost of local block scapes.
All the above was done quickly, and there many nits about it, the main
point is that solutions can vary depending on the question and
background cited. No background, people need to presume things about
what answer you are seeking.
--
HLS