Timer locked when holding mouse down (WinNT)

I have a MDI application which uses MultiDocTemplate as well.

My CFormView derived class contains a timer proc which is interrupted by some events; like holding down the mouse button on the window's title bar. This is what I want to avoid (my timer proc. which does audio playback CAN'T be interrupted).
Remark: By "holding down the mouse button" I also mean: not moving the mouse. If I move the mouse (thus the window) then the timer proc gets called.

I tried to implement a CWinThread to handle the events as shown in the MTBounce sample code (which "bounces" a ball even when holding the mouse down on the window's title bar).

The difference is that the MTBounce sample doesn't use a MultiDocTemplate. So I've put the creation of my Thread (which must create itself the CFormView derived object) in the "OnCreateClient" proc of my CMDIChilWindow derived class.

The problem is: it makes no difference, the same events are "locking" the application and prevent the timer proc to run.

I'm quite new to MFC programming but I think I correctly applied the source code of MTBounce in my app, except that I'm not sure at all regarding what MultiDocTemplate could do to interfere.

Thanks to all.
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

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.

Are you using the timer via the WM_TIMER message, or a callback?

   Using the WM_TIMER message means thay your app will not process the message unless it is pumping it's message queue.

   Try using a timer with a callback function.

   You could also create a simple (non-UI) worker thread to handle the audio playback.

-=- James.
SergeDePauwAuthor Commented:
Thanks for you quick answert but...

I tried using the timer via WM_TIMER and via a callback timer proc and it does the same: as soon as I hold the mouse button on the window's title bar, my timer proc is not called anymore.

I would prefer not to use a worker thread because my timer will not only play audio but also display a progress bar, handle sound file auto-chain and so on... So I think I really need a thread that handles the events for my window, letting the main thread running normally whatever the user is doing with the mouse or keyboard.
Tommy HuiEngineerCommented:
I suspect your are not using the form of timers that is not message based. Make sure you are doing this:

      m_TimerId = ::SetTimer(NULL, NULL, 1000, MyTimerProc);

and that MyTimerProc is doing this:

void CALLBACK MyTimerProc(HWND hwnd, UINT msg, UINT idEvent, DWORD dwTime)
      TRACE("0x%08X  msg: %d  id: %d  time:%d\r\n", hwnd, msg, idEvent, dwTime);

Then if you run this in the debugger, you'll see that the function is called even when you are dragging the window around.

CompTIA Network+

Prepare for the CompTIA Network+ exam by learning how to troubleshoot, configure, and manage both wired and wireless networks.

SergeDePauwAuthor Commented:
I tried both using MFC's SetTimer for a callback timer proc and the one you show: the results are the same.
Let just me remind you: if I MOVE the window: it works; the problem comes up only if the mouse button is down and the mouse DOESN'T MOVE.

Anyway, the MTBounce sample code doesn't use a callback timer but a WM_TIMER message based proc located in the window class.
I guess that it is much easier to access the view's and other object's globals so I think I need to do it the same way.

I experienced further more and I think I found the reason to my problem (but not the solution, so I still need you guys !):

- When I place the "SetTimer" in the same proc where I create the view (in my CWinThread derived class): the timer is still locked by the "mouse button down on wdw title"
- When I call "SetTimer" in the "InitInstance" proc: it works just fine !

So the solution to my problem is to find a way to implement a CWinThread in a MDI / CMultiDocTemplate application.

Here are some details about what I've done so far.

As MTBounce sample doesn't use resources or DocTemplates, it simply implements a "direct" creation of the CMDIChildWindow which itself creates the CWinThread, which itself creates the CWnd (in the "InitInstance" proc of the Thread).

I tried to implement the same hierarchy BUT I wasn't able to create my CFormView in the InitInstance of my Thread (because I use resources and multidoctemplate). Instead, this is what I've done:

- CChildFrame derived from CMDIChildWnd
- CPresetThread derived from CWinThread
- CTestFormView derived from CFormView

I overided "OnCreateClient" in CChildFrame where I replaced the creation of CTestFormView by the creation of CPresetThread as follow:

CPresetThread* pPresetThread = new CPresetThread(m_hWnd);

Right after that, I also call my own proc in CPresetThread in order to create the CTestFormView:

m_TestFormView = pPresetThread->CreateView(this, pContext, AFX_IDW_PANE_FIRST);

"OnCreateClient" is the best place I found to put this call because this is where I have access to the CCreateContext object (created by the CMultiDocTemplate).

I figured out that CPresetThread::InitInstance is only called later on (I expected it to be called during "CreateThread()" but it seems it is not the case).
If I relate this to the "SetTimer" call experience, the creation of the CTestFormView is made too soon.

As I don't know where else I could create CTestFormView: does anyone know how I should proceed from there ?

Other solutions to my problem could be:

1. to create the CWinThread independently from the rest and "assigning" it a window to handle events afterwords. But I'm not sure this is possible.

2. create the CTestFormView (from a dialog resource) directly in the InitInstance and assigning it afterwords in the doctemplate.

Did anyone succeed in implementing a CWinThread in a MDI / CMultiDocTemplate application ? Isn't that a "common need" ?

Tommy HuiEngineerCommented:
Okay, I see your problem now. When the mouse is clicked without moving the mouse, the timer callback isn't called. You can only achieve your results with a thread. You should take a look at the O'Reilly book Win32 Multithreaded Programming. Look specifically at chapter 13 at the Animator program.

SergeDePauwAuthor Commented:
Yes,...and No.
As I said, I finally made the timer proc work (even whit mouse-click without moving the mouse): if I put the "SetTimer" call in the "InitInstance" of my Thread-derivec class.

I need a user-interface Thread (not a simple timer proc) and it seems the problem is to make a CWinThread handle events for a View that is normally created by the CMultiDocTemplate.

I'll try to find the book you're talking about, but in the meantime, if anyone knows the way to achieve that...
  If you want a thread to manipulate controls in another window (hence another Message Queue) you are going to have to pass the HWNDs of the controls it needs to manipulate to the thread.

   The thread can sit in a tight loop, looping every (for example) 100ms and preform whatever updates you need.

   What you as can be done, of couse, but I need you to specify exactly what controls and "events" you will need to manipulate and/or work with in the thread.

-=- James.

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
Basically, it looks something like this:

// Data To Pass To Thread...
struct  SThreadData
    CMyView m_*pView;
    HWND    m_hWndProgress;
    HWND    m_hWndStatus;
(Pass MyThreadProc a pointer to a populated SThreadData structure: AfxBeginThread( MyThreadProc, pTData ) )

UINT    MyThreadProc( VOID *pParam )
    SThreadData     *pTData = (SThreadData*)pParam;// Get Thread Data
    CMyView         *pThis = pTData -> m_pView;    // Get "this" Pointer
    CProgressCtrl   pgProgress;
    CStatic         scStatus;
    CString         sMessage;
    int             iPercent;

    pgProgress.Attach( pTData -> m_hWndProgress ); // Attach Object To Window
    scStatus.Attach( pTData -> m_hWndStatus );     // Attach Object To Window

    while( !ms_bAppDone )                          // While Not Done
        pThis -> UpdateAudioData();                // Update Audio
        iPercent = pThis -> GetAudioDataDone();    // Get Percentage
        sMessage.Format( "Audio Data %d%% Done",
            iPercent );                            // Format Message
        pgProgress.SetPos( iPercent );             // Set Progress Pos
        scStatus.SetWindowText( sMessage );        // Set Status Message
        Sleep( 100 );                              // Sleep Until Next Update

SergeDePauwAuthor Commented:
This is not exactly what I wanted to do but I combined your idea with another sample code I found and I think that will do the job.

I also now have the book "thui" told me about. It seems to be very interesting and I'm sure it will also be helpfull.

Thanks to all for your help.
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.