电源注册过程:
1、DevicePowerNotify
Sends a request to the Power Manager about changing a power state
of a peripheral device.
2、RequestPowerNotifications (注册电源管理器)
Registers a message queue to receive power change notifications .
3、StopPowerNotifications
Stops receiving power change notifications .
4、SetPowerRequirement
Informs the Power Manager about power requirements of a given peripheral device .
5、ReleasePowerRequirement
Informs Power Manager that it can release previously set power re- quirements of a given peripheral device .
6. SetSystemPowerState
A request sent to the Power Manager about changing a power state of the system as a whole .
IOCTL:
PM Example:
// // Copyright (c) Microsoft Corporation. All rights reserved. // // // Use of this source code is subject to the terms of the Microsoft // premium shared source license agreement under which you licensed // this source code. If you did not accept the terms of the license // agreement, you are not authorized to use this source code. // For the terms of the license, please see the license agreement // signed by you and Microsoft. // THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES. // /*++ Module Name: api.c Abstract: Power Manager API runthrough test (defunct). Notes: Revision History: --*/ #include <windows.h> #include <msgqueue.h> #include <pm.h> extern int CreateArgvArgc(TCHAR *pProgName, TCHAR *argv[20], TCHAR *pCmdLine); typedef enum _Cmd { TEST_INFINITE = 'i', TEST_ONCE = 'o', PREMATURE_RELEASE = 'p', } CMD; #define QUEUE_ENTRIES 3 #define MAX_NAMELEN 200 #define QUEUE_SIZE (QUEUE_ENTRIES * (sizeof(POWER_BROADCAST) + MAX_NAMELEN)) HANDLE hMsgQ; DWORD WINAPI PowerNotifyThread( LPVOID Context ); #ifdef DEBUG DBGPARAM dpCurSettings = { TEXT("PMAPI"), { TEXT("Error"), TEXT("Warn"), TEXT("Thread"), TEXT("Trace") TEXT("5"), TEXT("6"), TEXT("7"), TEXT("8") TEXT("9"), TEXT("10"), TEXT("11"), TEXT("12") TEXT("13"), TEXT("14"), TEXT("15"), TEXT("16") }, 0x0007 // ZONE_WRN|ZONE_ERR|ZONE_THREAD }; #define ZONE_ERR DEBUGZONE(0) #define ZONE_WRN DEBUGZONE(1) #define ZONE_THREAD DEBUGZONE(2) #define ZONE_TRACE DEBUGZONE(3) #endif // DEBUG DWORD MyEnumRegValues( HKEY hKey, LPCWSTR pState, DWORD Len ) { WCHAR wsValBuff[MAX_PATH]; BYTE bData[MAX_PATH]; DWORD iValue, dwValBuffLen, dwType, dwDataLen; DWORD dwErr = ERROR_SUCCESS; for (iValue = 0; ERROR_SUCCESS == dwErr; iValue++) { memset(&wsValBuff, 0, MAX_PATH); dwValBuffLen = MAX_PATH; dwType = 0; memset(&bData, 0, MAX_PATH); dwDataLen = MAX_PATH; dwErr = RegEnumValue(hKey, iValue, &wsValBuff[0], &dwValBuffLen, NULL, &dwType, &bData[0], &dwDataLen); if (ERROR_SUCCESS == dwErr) { if (pState && dwType == REG_DWORD && sizeof(DWORD) == dwDataLen && 0 == wcsncmp(PM_FLAGS_SZ, wsValBuff, dwValBuffLen)) { DWORD Flags = *(PDWORD)bData; switch (POWER_STATE(Flags)) { case POWER_STATE_OFF: DEBUGMSG(ZONE_TRACE, (TEXT("'%s' is a POWER_STATE_OFF\n"), pState)); continue; case POWER_STATE_SUSPEND: DEBUGMSG(ZONE_TRACE, (TEXT("'%s' is a POWER_STATE_SUSPEND\n"), pState)); continue; } } } else if (ERROR_NO_MORE_ITEMS != dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!\tRegEnumValue ERROR:%d dwType:%d\n"), dwErr, dwType)); } } return (dwErr == ERROR_NO_MORE_ITEMS ? ERROR_SUCCESS : dwErr); } /*++ System power state processing sample. --*/ DWORD MyProcessSystemPowerStates( VOID ) { WCHAR wsKeyBuff[MAX_PATH]; DWORD dwKeyBuffLen; DWORD dwSubErr; DWORD dwErr; int iKey; HKEY hKey; // open the power manager's state keys // _stprintf(wsKeyBuff, _T("%s\\State"), PWRMGR_REG_KEY); dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wsKeyBuff, 0, 0, &hKey); // enumerate the subkeys // for (iKey = 0; ERROR_SUCCESS == dwErr; iKey++) { memset(&wsKeyBuff, 0, MAX_PATH); dwKeyBuffLen = MAX_PATH; dwErr = RegEnumKeyEx(hKey, iKey, &wsKeyBuff[0], &dwKeyBuffLen, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS == dwErr) { HKEY hSubKey; // open the subkey // dwSubErr = RegOpenKeyEx(hKey, &wsKeyBuff[0], 0, 0, &hSubKey); if (ERROR_SUCCESS != dwSubErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!RegOpenKeyEx ERROR:%d\n"), dwSubErr)); break; } // enumerate the values // dwSubErr = MyEnumRegValues(hSubKey, wsKeyBuff, dwKeyBuffLen); if (hSubKey) RegCloseKey(hSubKey); // subkeys name the system states, so set them... // DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetSystemPowerState:%s\n"), wsKeyBuff)); dwErr = SetSystemPowerState(wsKeyBuff, 0, 0); if (ERROR_SUCCESS != dwErr && ERROR_CANCELLED != dwErr && ERROR_SET_POWER_STATE_VETOED != dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetSystemPowerState ERROR:%d ***\n"), dwErr)); RegCloseKey(hSubKey); break; } DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetSystemPowerState:%s, POWER_FORCE\n"), wsKeyBuff)); dwErr = SetSystemPowerState(wsKeyBuff, 0, POWER_FORCE); if (ERROR_SUCCESS != dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetSystemPowerState ERROR:%d ***\n"), dwErr)); RegCloseKey(hSubKey); break; } } else if (ERROR_NO_MORE_ITEMS != dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!RegEnumKeyEx ERROR: %d \n"), dwErr)); } } if (hKey) RegCloseKey(hKey); return (dwErr == ERROR_NO_MORE_ITEMS ? ERROR_SUCCESS : dwErr); } // Simple test app // int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmShow) { TCHAR *argv[20]; int argc; CMD cCmd = 0; MSGQUEUEOPTIONS msgOptions = {0}; MEMORYSTATUS m1 = {0}, m2 = {0}; DWORD dwErr; HANDLE hReq = NULL; HANDLE hNotifications; CEDEVICE_POWER_STATE Dx; HANDLE hPrev; HANDLE hThread; DWORD dwTest = 1; BOOL bDone = FALSE; WIN32_FIND_DATA fd; DWORD device; UNREFERENCED_PARAMETER(hInst); UNREFERENCED_PARAMETER(hPrevInst); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmShow); DEBUGREGISTER(NULL); // // parse command line // argc = CreateArgvArgc(TEXT( "PMAPI" ), argv, lpCmdLine); if (argc >= 2) { if (!swscanf(argv[1], TEXT("%c"), &cCmd )) cCmd = 0; } switch (cCmd) { case TEST_ONCE: case TEST_INFINITE: case PREMATURE_RELEASE: break; default: { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI <Command>\n"))); DEBUGMSG(ZONE_ERR, (TEXT(" where <Command> is one of\n"))); DEBUGMSG(ZONE_ERR, (TEXT(" %c : Infinite test pass\n"), TEST_INFINITE)); DEBUGMSG(ZONE_ERR, (TEXT(" %c : One-shot test pass\n"), TEST_ONCE)); DEBUGMSG(ZONE_ERR, (TEXT(" %c : Premature exit test pass\n"), PREMATURE_RELEASE)); } return 0; } // snap mem // GlobalMemoryStatus(&m1); DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!Before PM API Tests: Virtual Memory = %ld\n"), m1.dwAvailVirtual)); // // create a message queue for device notifications // msgOptions.dwSize = sizeof(MSGQUEUEOPTIONS); msgOptions.dwFlags = 0; msgOptions.cbMaxMessage = QUEUE_SIZE; msgOptions.bReadAccess = TRUE; hMsgQ = CreateMsgQueue(NULL, &msgOptions); if (!hMsgQ) { dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!CreateMessageQueue ERROR:%d\n"), dwErr)); return dwErr; } // request Power notifications // hNotifications = RequestPowerNotifications(hMsgQ, POWER_NOTIFY_ALL); if (!hNotifications) { CloseMsgQueue(hMsgQ); dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!RequestPowerNotifications ERROR:%d\n"), dwErr)); return dwErr; } // start the notify thread // hThread = CreateThread(NULL, 0, PowerNotifyThread, NULL, 0, NULL ); if ( !hThread ) { dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!CreateThread ERROR:%d\n"), dwErr )); return -1; } do { DEBUGMSG(ZONE_ERR, (TEXT("\nPMAPI!************************ BEGIN PM API Test[%d]************************\n"), dwTest)); ///////////////////////////////////////////// // // Test : set every *named* system power state // dwErr = MyProcessSystemPowerStates( ); if (ERROR_SUCCESS != dwErr && ERROR_CANCELLED != dwErr && // cancelled by user dialog ERROR_SET_POWER_STATE_VETOED != dwErr ) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!MyProcessSystemPowerStates ERROR.1:%d\n"), dwErr)); break; } ///////////////////////////////////////////// // // Test: SetSystemPowerState: by flags // DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetSystemPowerState:POWER_STATE_SUSPEND, POWER_FORCE\n"))); dwErr = SetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE); if (ERROR_SUCCESS != dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!SetSystemPowerState ERROR.1:%d\n"), dwErr)); break; } ///////////////////////////////////////////// // // Test: SetSystemPowerState: invalid states // DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetSystemPowerState:abcde\n"))); dwErr = SetSystemPowerState(L"abcde", 0, 0); if (ERROR_SUCCESS == dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetSystemPowerState ERROR.2:%d ****\n"), dwErr)); break; } DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetSystemPowerState: 123 \n"))); dwErr = SetSystemPowerState(L" 123 ", 0, 0); if (ERROR_SUCCESS == dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetSystemPowerState ERROR.2:%d ****\n"), dwErr)); break; } ///////////////////////////////////////////// // // Test: SetPowerRequirement: invalid parameters // dwErr = ERROR_SUCCESS; for (Dx = PwrDeviceUnspecified; Dx <= PwrDeviceMaximum; Dx++) { HANDLE h; // *INVALID* parameter DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetPowerRequirement:#$%#$\n"))); h = SetPowerRequirement(L"#$%#$", // *INVALID* DeviceName Dx, // DeviceState, POWER_NAME, // DeviceFlags NULL, 0); if (h) { dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetPowerRequirement ERROR.3.1:%d ****\n"), dwErr)); break; } // *INVALID* parameter DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetPowerRequirement:PwrDeviceMaximum\n"))); h = SetPowerRequirement(L"DSK1:", // DeviceName Dx, // DeviceState, 0, // *INVALID* Flags NULL, 0); if (h) { dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetPowerRequirement ERROR.3.2:%d ****\n"), dwErr)); break; } } if (ERROR_SUCCESS != dwErr) break; ///////////////////////////////////////////// // // Test: SetPowerRequirement: make sure we always get the same handle in this process // hPrev = hReq = NULL; for ( Dx = D0; Dx < PwrDeviceMaximum; Dx++) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetPowerRequirement:DSK1:\n"))); hReq = SetPowerRequirement(L"DSK1:", // DeviceName Dx, // DeviceState, POWER_NAME, // Flags NULL, 0); if (!hReq) { dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetPowerRequirement ERROR.3.3:%d, Dx:%d****\n"), dwErr, Dx)); break; } if (hPrev && (hPrev != hReq)) { dwErr = ERROR_GEN_FAILURE; DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!*** SetPowerRequirement ERROR.3.4:%d, hPrev:0x%x, hReq:0x%x ****\n"), dwErr, hPrev, hReq)); break; } hPrev = hReq; } if (ERROR_SUCCESS != dwErr) break; DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!ReleasePowerRequirement\n"))); dwErr = ReleasePowerRequirement(hReq); if (ERROR_SUCCESS != dwErr) break; ///////////////////////////////////////////// // // Test: SetPowerRequirement: on *all devices* // for (device = 0; ; device++) { memset(&fd, 0, sizeof(fd)); if ( !GetDeviceByIndex(device, &fd) ) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!GetDeviceByIndex: no more devices:%d\n"), device)); break; } for (Dx = D0; Dx < PwrDeviceMaximum; Dx++) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetPowerRequirement:'%s', D%d\n"), fd.cFileName, Dx)); hReq = SetPowerRequirement(fd.cFileName, // DeviceName Dx, // DeviceState, POWER_NAME, // Flags NULL, 0); if ( !hReq ) { dwErr = GetLastError(); DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!*** SetPowerRequirement Device:'%s', Dx:%d, ERROR.4:%d ****\n"), fd.cFileName, Dx, dwErr)); if (fd.cFileName[0] != 0) // NULL name? break; else dwErr = ERROR_SUCCESS; } } if (ERROR_SUCCESS != dwErr) break; DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!ReleasePowerRequirement\n"))); dwErr = ReleasePowerRequirement(hReq); if (ERROR_SUCCESS != dwErr) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!ReleasePowerRequirement ERROR:%d\n"), dwErr)); if (hReq) break; else dwErr = ERROR_SUCCESS; } } if (ERROR_SUCCESS != dwErr) break; ///////////////////////////////////////////// // // Test : simulate DevicePowerNotify on all devices // for (device = 0; ; device++) { memset(&fd, 0, sizeof(fd)); if ( !GetDeviceByIndex(device, &fd) ) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!GetDeviceByIndex: no more devices:%d\n"), device)); break; } for (Dx = D0; Dx < PwrDeviceMaximum; Dx++) { dwErr = DevicePowerNotify(fd.cFileName, // DeviceName Dx, // DeviceState, POWER_NAME // Flags ); if ( ERROR_SUCCESS != dwErr ) { // this error code was propogated from the named device, so don't abort DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!*** DevicePowerNotify Device:'%s', Dx:%d, ERROR:%d ****\n"), fd.cFileName, Dx, dwErr)); } } } dwErr = ERROR_SUCCESS; ///////////////////////////////////////////// // // Test: set device requirement on *all devices*, then adjust the system power level // // .... ///////////////////////////////////////////// // // Test: set device requirement on *all* devices, then exit prematurely // for (device = 0; ;device++) { memset(&fd, 0, sizeof(fd)); if ( !GetDeviceByIndex(device, &fd) ) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!GetDeviceByIndex: no more devices:%d\n"), device)); break; } for (Dx = D0; Dx < PwrDeviceMaximum; Dx++) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!SetPowerRequirement:'%s'\n"), fd.cFileName)); hReq = SetPowerRequirement(fd.cFileName, // DeviceName Dx, // DeviceState, POWER_NAME, // Flags 0, 0); if ( !hReq ) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!*** SetPowerRequirement on Device:'%s', Dx:%d, ERROR.0:%d ****\n"), fd.cFileName, Dx, GetLastError())); if (fd.cFileName[0] != 0) // NULL name? break; else dwErr = ERROR_SUCCESS; } // drop them all on the floor to see if PM will clean it up } } switch(cCmd) { case PREMATURE_RELEASE: exit(0); case TEST_INFINITE: Sleep(500); break; default: bDone = TRUE; break; } DEBUGMSG(ZONE_ERR, (TEXT("\nPMAPI!************************ END PM API Test[%d] ************************\n"), dwTest++)); } while (!bDone); DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!StopPowerNotifications\n"))); if ( !StopPowerNotifications(hNotifications) ) { DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!StopNotifications ERROR:%d\n"), GetLastError())); } CloseMsgQueue(hMsgQ); // snap mem // GlobalMemoryStatus(&m2); DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!After PM API Tests: Virtual Memory = %ld\n"), m2.dwAvailVirtual)); if ((m2.dwAvailVirtual < m1.dwAvailVirtual)) { DEBUGMSG(ZONE_TRACE, (TEXT("PMAPI!\n\n*** PM API Leaked: Physical Memory = %ld, Virtual Memory = %ld ***\n"), (m1.dwAvailPhys - m2.dwAvailPhys), (m1.dwAvailVirtual - m2.dwAvailVirtual))); } if (ERROR_SUCCESS != dwErr) { DEBUGMSG(ZONE_ERR, (TEXT("\n\n*** PMAPI TEST FAILED:%d ****\n\n"), dwErr)); } else { DEBUGMSG(ZONE_ERR, (TEXT("\n\n*** PMAPI TEST PASSED ****\n\n"))); } return 1; } int GetPriority( VOID ) { return 251; // THREAD_PRIORITY_NORMAL } DWORD WINAPI PowerNotifyThread( LPVOID Context ) { DWORD dwErr, dwFlags = 0, dwCount = 0; DWORD dwPri = 0; UCHAR buf[QUEUE_SIZE]; int iBytesInQueue; const int ci = sizeof(POWER_BROADCAST); dwPri = GetPriority(); if ( !CeSetThreadPriority(GetCurrentThread(), dwPri)) { dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!CeSetThreadPriority ERROR:%d\n"), dwErr)); ExitThread(dwErr); return dwErr; } do { iBytesInQueue = 0; memset(&buf, 0, QUEUE_SIZE); // Block on our message queue. // This thread runs when the power manager writes a notification into the queue. if ( !ReadMsgQueue(hMsgQ, &buf, QUEUE_SIZE, &iBytesInQueue, INFINITE, // Timeout &dwFlags)) { dwErr = GetLastError(); DEBUGMSG(ZONE_ERR, (TEXT("PMAPI!ReadMsgQueue: ERROR:%d\n"), dwErr)); break; } else { // // process power notifications // PPOWER_BROADCAST pB = (PPOWER_BROADCAST)&buf; while (iBytesInQueue > 0 && iBytesInQueue > ci) { DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!*** Power Notification @ Tick:%u, Count:%d, Pri:%d***\n"), GetTickCount(), dwCount++, CeGetThreadPriority(GetCurrentThread()))); DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tMessage: 0x%x\n"), pB->Message)); DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tFlags: 0x%x\n"), pB->Flags)); DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tdwLen: %d\n"), pB->Length)); DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tSystemPowerState: '%s'\n"), pB->SystemPowerState)); switch (pB->Message) { case PBT_TRANSITION: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPBT_TRANSITION\n"))); switch (POWER_STATE(pB->Flags)) { case POWER_STATE_ON: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPOWER_STATE_ON\n"))); break; case POWER_STATE_OFF: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPOWER_STATE_OFF\n"))); break; case POWER_STATE_CRITICAL: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPOWER_STATE_CRITICAL\n"))); break; case POWER_STATE_BOOT: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPOWER_STATE_BOOT\n"))); break; case POWER_STATE_IDLE: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPOWER_STATE_IDLE\n"))); break; case POWER_STATE_SUSPEND: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPOWER_STATE_SUSPEND\n"))); break; case POWER_STATE_RESET: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPOWER_STATE_RESET\n"))); break; default: DEBUGMSG(ZONE_THREAD,(TEXT("PMAPI!\tUnknown Power State:0x%x\n"),pB->Flags)); ASSERT(0); break; } break; case PBT_RESUME: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPBT_RESUME\n"))); break; case PBT_POWERSTATUSCHANGE: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tPBT_POWERSTATUSCHANGE\n"))); break; default: DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!\tInvalid Message:%d\n"), pB->Message)); ASSERT(0); break; } DEBUGMSG(ZONE_THREAD, (TEXT("PMAPI!***********************\n"))); iBytesInQueue -= ci + pB->Length; pB += ci + pB->Length; } } } while (1); ExitThread(ERROR_SUCCESS); return ERROR_SUCCESS; } // EOF