//========================================================================
//TITLE:
//    CPowerThread更新至v1.1.0
//AUTHOR:
//    norains
//DATE:
//    Tuesday  25-December-2007
//Environment:
//    EVC4.0 + Windows CE 5.0 Standard SDK
//    EVC4.0 + SDK-WINCE5.0-MIPSII
//    VS2005 + SDK-WINCE5.0-MIPSII   
//========================================================================

    相对于v1.0.0版本,有如下变动:
   
    1.去掉GetInstance()函数,不用获取对象实例,可以直接声明对象实例使用
   
    2.改进该类以令其在继承之后能正常工作.
   
    3.增加OnNotifyPower()函数,可以不设置回调函数而通过重载该函数监视电源的变化.
   
    v1.0.0版本:http://blog.csdn.net/norains/archive/2007/07/20/1700980.aspx 


//////////////////////////////////////////////////////////////////////
// PowerThread.h: interface for the CPowerThread class.
//
//Version:
//    1.1.0
//Date:
//    2007.11.15
//////////////////////////////////////////////////////////////////////

#ifndef POWERTHREAD_H
#define POWERTHREAD_H



#include 
"Pm.h"



//-----------------------------------------------------------------
//Enum data type
enum PowerStatusType
{
    POW_UNKNOW,        
//Unknow the status
    POW_CHARGING,    //It's charging now
    POW_CHARGEFULL,    //Full charge
    POW_VLOW,        //The battery level is very low
    POW_LOW,
    POW_NORMAL,
    POW_HIGH,
    POW_VHIGH        
//The battery level is very high
};
//----------------------------------------------------------------

class CPowerThread  
{
public:
    BOOL ResumnSign(); 
//Not support now
    void GetCallbackFunction(void (* *pCallbackFunc)(PowerStatusType powStatus, int iBatteryPercent));
    
void SetCallbackFunction(void (*pCallbackFunc)(PowerStatusType powStatus, int iBatteryPercent));
    
void StopCapture();
    BOOL StartCapture();
    BOOL GetRunStatus();
    
void SetTimeout(ULONG ulTime);
    
    CPowerThread();
    
virtual ~CPowerThread();


protected:
    
virtual void OnNotifyPower(PowerStatusType powStatus, int iBatteryPercent);
        
    
    
//The critical section function
    inline void    InitLock()    { InitializeCriticalSection(&m_csLock); }
    inline 
void LockThis()    { EnterCriticalSection(&m_csLock);      }    
    inline 
void    UnLockThis()  { LeaveCriticalSection(&m_csLock);      }
    inline 
void    DelLock()     { DeleteCriticalSection(&m_csLock);     }


private:
    PowerStatusType GetPowerStatus(PPOWER_BROADCAST pPowerInfo, 
int *piPercent);
    
static DWORD WINAPI PowerThread(PVOID pArg);

    BOOL m_bExitThread;
    ULONG m_ulWaitTime;
    BOOL m_bRunning;
    CRITICAL_SECTION m_csLock;

    
//This is for callback function.
    void (*m_pNotifyPower)(PowerStatusType powStatus, int iBatteryPercent);
};

#endif //#ifndef POWERTHREAD_H

 
//////////////////////////////////////////////////////////////////////   
// PowerThread.cpp: implementation of the CPowerThread class.
//
//////////////////////////////////////////////////////////////////////

#include 
"stdafx.h"
#include 
"PowerThread.h"
#include 
"Msgqueue.h"


//--------------------------------------------------------------------
//Macro define
#define DEFAULT_TIMEOUT        1000//1000ms

//----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPowerThread::CPowerThread():
m_bExitThread(TRUE),
m_ulWaitTime(DEFAULT_TIMEOUT),
m_bRunning(FALSE),
m_pNotifyPower(NULL)
{
    InitLock();
}

CPowerThread::
~CPowerThread()
{
    DelLock();
}



//------------------------------------------------------------------
//Description:
//    Get the level of power from the PPOWER_BROADCAST struct
//
//Parameters:
//    pPowerInfo:[in] The struct includes the power information
//    piPercent:[out] The battery life percent.
//
//Return Values:
//    The power status
//----------------------------------------------------------------
PowerStatusType CPowerThread::GetPowerStatus(PPOWER_BROADCAST pPowerInfo, int *piPercent)
{
    PowerStatusType powStatus 
= POW_UNKNOW;

    
if ( !pPowerInfo )
    {
        
return POW_UNKNOW;
    }
    
    PPOWER_BROADCAST_POWER_INFO ppbpi 
= (PPOWER_BROADCAST_POWER_INFO) pPowerInfo->SystemPowerState;
    
if ( !ppbpi )
    {
        
return POW_UNKNOW;
    }
    
    
*piPercent = ppbpi->bBatteryLifePercent; 
    
    
if(ppbpi->bACLineStatus == AC_LINE_ONLINE)
    {        
        
if(ppbpi->bBatteryFlag == BATTERY_FLAG_CHARGING)
        {
            
//Charging
            powStatus = POW_CHARGING;
        }
        
else
        {
            
//May be full charging,or may be no battery
            powStatus = POW_CHARGEFULL;
        }
    }
    
else
    {
        
//Use battery
    
        
if(0 <= ppbpi->bBatteryLifePercent && ppbpi->bBatteryLifePercent <= 20)
        {
            powStatus 
= POW_VLOW;
        }
        
else if(20 < ppbpi->bBatteryLifePercent && ppbpi->bBatteryLifePercent <= 40)
        {
            powStatus 
= POW_LOW;
        }
        
else if(40 < ppbpi->bBatteryLifePercent && ppbpi->bBatteryLifePercent <=60)
        {
            powStatus 
= POW_NORMAL;
        }
        
else if(60 < ppbpi->bBatteryLifePercent && ppbpi->bBatteryLifePercent <=80)
        {
            powStatus 
= POW_HIGH;
        }
        
else if(80 < ppbpi->bBatteryLifePercent && ppbpi->bBatteryLifePercent <= 100)
        {
            powStatus 
= POW_VHIGH;
        }
        
else
        {
            powStatus 
= POW_UNKNOW;
        }
    }

    
return powStatus;
}




//------------------------------------------------------------------
//Description:
//    Thread to get the power status
//----------------------------------------------------------------
DWORD WINAPI CPowerThread::PowerThread(PVOID pArg)
{
    CPowerThread 
*pObject = (CPowerThread *) pArg;

    pObject
->m_bRunning = TRUE;

    BYTE pbMsgBuf[
sizeof(POWER_BROADCAST) + sizeof(POWER_BROADCAST_POWER_INFO)];
    PPOWER_BROADCAST ppb 
= (PPOWER_BROADCAST) pbMsgBuf;
    MSGQUEUEOPTIONS msgopts;
    
    
// Create our message queue
    memset(&msgopts, 0sizeof(msgopts));
    msgopts.dwSize 
= sizeof(msgopts);
    msgopts.dwFlags 
= 0;
    msgopts.dwMaxMessages 
= 0;
    msgopts.cbMaxMessage 
= sizeof(pbMsgBuf);
    msgopts.bReadAccess 
= TRUE;
    
    HANDLE rghWaits[
1= { NULL };
    rghWaits[
0= CreateMsgQueue(NULL, &msgopts);
    
if (!rghWaits[0])
    {
        
//erro
        return 0x10;
    
    }
    
    HANDLE hReq 
= NULL;
    
// Request notifications
    hReq = RequestPowerNotifications(rghWaits[0], PBT_POWERINFOCHANGE);
    
if (!hReq)
    {
        CloseHandle( rghWaits[ 
0 ] );
        
//erro
        return 0x15;

    }      
    


    
while(pObject->m_bExitThread == FALSE)
    {
        

        DWORD dwWaitCode 
= MsgWaitForMultipleObjectsEx( 1, rghWaits, pObject->m_ulWaitTime, QS_ALLINPUT, MWMO_INPUTAVAILABLE );
        
if ( dwWaitCode == WAIT_OBJECT_0 )
        {              
            DWORD dwSize, dwFlags;
            BOOL bReadResult 
= ReadMsgQueue(rghWaits[0], ppb, sizeof(pbMsgBuf), &dwSize, 0&dwFlags);
            
if (bReadResult == TRUE)
            {
                
int iPowPercent;
                PowerStatusType powStatus 
= pObject->GetPowerStatus(ppb,&iPowPercent);

                pObject
->LockThis();
                
if(pObject->m_pNotifyPower != NULL)
                {
                    pObject
->m_pNotifyPower(powStatus,iPowPercent);
                }
                pObject
->OnNotifyPower(powStatus,iPowPercent);
                pObject
->UnLockThis();

            }
            
else
            {
                
// We should never get here
                break;                
            }
        }


    }
    pObject
->m_bRunning = FALSE;
    
    
return 0;
}




//------------------------------------------------------------------
//Description:
//    Set the timeout for the wait thread.  It is only for the MsgWaitForMultipleObjectsEx()
//The default value is DEFAULT_TIMEOUT
//----------------------------------------------------------------
void CPowerThread::SetTimeout(ULONG ulTime)
{
    m_ulWaitTime 
= ulTime;
}


//------------------------------------------------------------------
//Description:
//    Get the status of thread
//
//Return Values:
//    TRUE: The thread is running for capturing the power status.
//    FALSE: No thread running.
//----------------------------------------------------------------
BOOL CPowerThread::GetRunStatus()
{
    
return m_bRunning;
}


//------------------------------------------------------------------
//Description:
//    start capturing the power status.If there is thread running,
//it will return FALSE;
//
//------------------------------------------------------------------
BOOL CPowerThread::StartCapture()
{
    
if(m_bRunning == TRUE)
    {
        
return FALSE;
    }

    m_bExitThread 
= FALSE;

    
//Create the thread for batter sampled    
    DWORD dwPwrThdID;
    HANDLE hdThrd 
= CreateThread(NULL,0,PowerThread,(void *)this,0,&dwPwrThdID);
    
if(hdThrd == NULL)
    {
        
return FALSE;
    }
    CloseHandle(hdThrd);

    
return TRUE;
}



//-----------------------------------------------------------------------------
//Description:
//    Stop capturing.
//
//--------------------------------------------------------------------------------
void CPowerThread::StopCapture()
{
    m_bExitThread 
= TRUE;
}


//------------------------------------------------------------------
//Description:
//    Set the callback function for receive the power status
//------------------------------------------------------------------
void CPowerThread::SetCallbackFunction(void (*pCallbackFunc)(PowerStatusType powStatus, int iBatteryPercent))
{
    LockThis();
    m_pNotifyPower 
= pCallbackFunc;
    UnLockThis();
}



//------------------------------------------------------------------
//Description:
//    Get the callback function
//------------------------------------------------------------------
void CPowerThread::GetCallbackFunction(void (* *pCallbackFunc)(PowerStatusType powStatus, int iBatteryPercent))
{
    LockThis();
    
*pCallbackFunc = m_pNotifyPower;
    UnLockThis();
}


//------------------------------------------------------------------
//Description:
//    Resumn the sign order to get the current power status,or the power
//status will return untill the power status changed.
//------------------------------------------------------------------
BOOL CPowerThread::ResumnSign()
{
    
/*
    BYTE pbMsgBuf[sizeof(POWER_BROADCAST) + sizeof(POWER_BROADCAST_POWER_INFO)];
    PPOWER_BROADCAST ppb = (PPOWER_BROADCAST) pbMsgBuf;
    MSGQUEUEOPTIONS msgopts;
    
    // Create our message queue
    memset(&msgopts, 0, sizeof(msgopts));
    msgopts.dwSize = sizeof(msgopts);
    msgopts.dwFlags = 0;
    msgopts.dwMaxMessages = 0;
    msgopts.cbMaxMessage = sizeof(pbMsgBuf);
    msgopts.bReadAccess = TRUE;
    
    HANDLE rghWaits[1] = { NULL };
    rghWaits[0] = CreateMsgQueue(NULL, &msgopts);
    if (!rghWaits[0])
    {
        //erro
        return FALSE;
    
    }
    

    // Request notifications
    HANDLE hReq = RequestPowerNotifications(rghWaits[0], PBT_POWERINFOCHANGE);
    if (!hReq)
    {
        CloseHandle( rghWaits[ 0 ] );
        //erro
        return FALSE;

    }      




    return TRUE;
    
*/


    
return FALSE;
}



//------------------------------------------------------------------
//Description:
//    Notify the power. It's used as call back funtion.
//------------------------------------------------------------------
void CPowerThread::OnNotifyPower(PowerStatusType powStatus, int iBatteryPercent)
{
    
return;
}