//------------------------------------------------------------------------------

// File: MsgThrd.h

//

// Desc: DirectShow base classes - provides support for a worker thread 

//       class to which one can asynchronously post messages.

//

// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.

//------------------------------------------------------------------------------





// Message class - really just a structure.

//

class CMsg {

public:

    UINT uMsg;

    DWORD dwFlags;

    LPVOID lpParam;

    CAMEvent *pEvent;



    CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt)

        : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {}



    CMsg()

        : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {}

};



// This is the actual thread class.  It exports all the usual thread control

// functions.  The created thread is different from a normal WIN32 thread in

// that it is prompted to perform particaular tasks by responding to messages

// posted to its message queue.

//

class AM_NOVTABLE CMsgThread {

private:

    static DWORD WINAPI DefaultThreadProc(LPVOID lpParam);

    DWORD               m_ThreadId;

    HANDLE              m_hThread;



protected:



    // if you want to override GetThreadMsg to block on other things

    // as well as this queue, you need access to this

    CGenericList<CMsg>        m_ThreadQueue;

    CCritSec                  m_Lock;

    HANDLE                    m_hSem;

    LONG                      m_lWaiting;



public:

    CMsgThread()

        : m_ThreadId(0),

        m_hThread(NULL),

        m_lWaiting(0),

        m_hSem(NULL),

        // make a list with a cache of 5 items

        m_ThreadQueue(NAME("MsgThread list"), 5)

        {

        }



    ~CMsgThread();

    // override this if you want to block on other things as well

    // as the message loop

    void virtual GetThreadMsg(CMsg *msg);



    // override this if you want to do something on thread startup

    virtual void OnThreadInit() {  };



    BOOL CreateThread();



    BOOL WaitForThreadExit(LPDWORD lpdwExitCode) {

        if (m_hThread != NULL) {

            WaitForSingleObject(m_hThread, INFINITE);

            return GetExitCodeThread(m_hThread, lpdwExitCode);

        }

        return FALSE;

    }



    DWORD ResumeThread() {

        return ::ResumeThread(m_hThread);

    }



    DWORD SuspendThread() {

        return ::SuspendThread(m_hThread);

    }



    int GetThreadPriority() {

        return ::GetThreadPriority(m_hThread);

    }



    BOOL SetThreadPriority(int nPriority) {

        return ::SetThreadPriority(m_hThread, nPriority);

    }



    HANDLE GetThreadHandle() {

        return m_hThread;

    }



    DWORD GetThreadId() {

        return m_ThreadId;

    }





    void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags,

                      LPVOID lpMsgParam, CAMEvent *pEvent = NULL) {

        CAutoLock lck(&m_Lock);

        CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent);

        m_ThreadQueue.AddTail(pMsg);

        

        if (m_lWaiting != 0) {

            ReleaseSemaphore(m_hSem, m_lWaiting, 0);

            m_lWaiting = 0;

        }

    }



    // This is the function prototype of the function that the client

    // supplies.  It is always called on the created thread, never on

    // the creator thread.

    //

    virtual LRESULT ThreadMessageProc(

        UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0;

};



