I started writing this as a how to monitor for system resume. But then I thought that a more general function that monitors for power state changes would be more useful. Many applications have reasons to monitor for Suspend and Resume transitions. 
There isn’t a good general way to monitor for Suspend, but applications can be notified when the system resumes. I do think that it would be good for applications to be notified on suspend so that they can save data just in case of power loss during suspend.
The way to monitor for power state changes from an application is to use message queues. Create the message queue using CreateMsgQueue(), then request power notifications using RequestPowerNotifications(). Then wait for the messages, in this case I assumed that this thread will run forever, so it just reads the message queue using ReadMsgQueue(), but it could also use WaitForSingleObject() or WaitForMultipleObjects() so that the thread can be notified that it should shutdown.
#include "Windows.h"
#include <pm.h>
#include <Msgqueue.h>
 
static DWORD WINAPI ResumeThread( LPVOID lpData)
{
                POWER_BROADCAST pwrStatus;
                MSGQUEUEOPTIONS PwrNotificationQ ;
                HANDLE hQ;
                int nBytesRead=0;
                DWORD dwFlags = 0;
 
                PwrNotificationQ.dwSize           = 5*sizeof(POWER_BROADCAST);
                PwrNotificationQ.dwFlags          = MSGQUEUE_NOPRECOMMIT ;
                PwrNotificationQ.dwMaxMessages    = 5 ;
                PwrNotificationQ.cbMaxMessage     = sizeof(POWER_BROADCAST) ;
                PwrNotificationQ.bReadAccess      = TRUE;
                hQ=CreateMsgQueue(NULL,&PwrNotificationQ);
                if(hQ==NULL)
                {
                                RETAILMSG( 1, (TEXT("Could not create message queue\n")));
                                return FALSE;
                }
                if(RequestPowerNotifications(hQ,PBT_RESUME)==NULL)
                {
                                RETAILMSG(1,(TEXT("RequestPowerNotifications failed\n")));
                                CloseHandle( hQ );
                                return FALSE;
                }
                memset( &pwrStatus, 0, sizeof( pwrStatus ));
 
                while(1)
                {
                                if ( !ReadMsgQueue(hQ,(LPVOID)&pwrStatus,sizeof(pwrStatus), &nBytesRead,INFINITE,&dwFlags) )
                                {
                                                RETAILMSG(1, (TEXT("ReadMsgQueue failed:%d\n"), GetLastError()));
                                }
                                else
                                {
                                                switch (pwrStatus.Message)
                                                {
                                                                case PBT_RESUME:
                                                                                RETAILMSG(1, (TEXT("PBT_RESUME\n")));
                                                                                break;
 
                                                                case PBT_POWERSTATUSCHANGE:
                                                                                RETAILMSG(1, (TEXT("PBT_POWERSTATUSCHANGE\n")));
                                                                                break;
 
                                                                case PBT_POWERINFOCHANGE:
                                                                                RETAILMSG(1, (TEXT("PBT_POWERSTATUSCHANGE\n")));
                                                                                break;
 
                                                                case PBT_TRANSITION:
                                                                                RETAILMSG(1, (TEXT("PBT_TRANSITION")));
                                                                                switch( POWER_STATE(pwrStatus.Flags) )
                                                                                {
                                                                                                case POWER_STATE_ON:
                                                                                                                RETAILMSG(1, (TEXT(" POWER_STATE_ON\n")));
                                                                                                                break;
                                                                                                case POWER_STATE_OFF:
                                                                                                                RETAILMSG(1, (TEXT(" POWER_STATE_OFF\n")));
                                                                                                                break;
                                                                                                case POWER_STATE_CRITICAL:
                                                                                                                RETAILMSG(1, (TEXT(" POWER_STATE_CRITICAL\n")));
                                                                                                                break;
                                                                                                case POWER_STATE_BOOT:
                                                                                                                RETAILMSG(1, (TEXT(" POWER_STATE_BOOT\n")));
                                                                                                                break;
                                                                                                case POWER_STATE_IDLE:
                                                                                                                RETAILMSG(1, (TEXT(" POWER_STATE_IDLE\n")));
                                                                                                                break;
                                                                                                case POWER_STATE_SUSPEND:
                                                                                                                RETAILMSG(1, (TEXT(" POWER_STATE_SUSPEND\n")));
                                                                                                                break;
                                                                                                case POWER_STATE_RESET:
                                                                                                                RETAILMSG(1, (TEXT(" POWER_STATE_RESET\n")));
                                                                                                                break;
                                                                                                default:
                                                                                                                break;
                                                                                }
                                                                                break;
 
                                                                default:
                                                                                break;
                                                }
                                }
                }
                StopPowerNotifications(hQ);
                CloseMsgQueue( hQ );
                return TRUE;
}
There are also cases where drivers may want to use message queues to be notified of system resume.   One case is when the driver doesn’t need to implement the XXX_PowerUp() and XXX_PowerDown() functions but does need to be notified that they system resumed.
This code does assume that the system includes the power manager and point-to-point message queues.
 
Copyright © 2009 – Bruce Eitman
All Rights Reserved